Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

neocoder

Standalone Neovim-native agentic coding assistant built from scratch in Lua.

Status

neocoder currently includes:

  • Command and keymap entrypoints
  • Turn orchestration (ask, search, visual_edit)
  • Typed plan schema + planner fallback strategy
  • Deterministic step execution
  • Policy + approval gates (read-only-first default)
  • Tool runtime (read_file, write_file, apply_patch, grep, glob, ls, bash, git, diagnostics)
  • Scoped child-task tool (task) with step/tool limits
  • Bounded subtask scheduler with depth and fanout limits
  • Provider adapters (opencode, codex, claude, azure_openai)
  • Project instruction file injection (neocoder.md / avante.md / .neocoder/instructions.md)
  • Prompt directive DSL (slash commands, mentions, shortcuts)
  • Adaptive scope inference (selection|file|module|repo|external) with prompt tags
  • Autonomous route planning with bounded subtasks
  • Retrieval pipeline with staged evidence collection, ranking, and dedupe
  • Repo map symbol extraction stage for retrieval
  • Optional RAG sidecar integration (rag_search tool + status surfaces)
  • Local daemon sidecar (scripts/neocoderd.py) for scope/index/verification acceleration
  • Verification gate for code-intent turns (verification.require_pass_for_success)
  • Dispatch-agent read-only sub-agent tool (dispatch_agent)
  • MCP stdio JSON-RPC runtime + dynamic registry + project lock + local/external surf hooks
  • Floating UI + optional workspace layout (ui.layout = "workspace")
  • Persistence in .neocoder/ (events, plan, state, patch artifacts)
  • Typed runtime events (step_start, tool_call, tool_result, tool_error, ...)

Install (local)

Example with lazy.nvim:

{
  dir = "/Users/divyansh/experiments/neocoder",
  config = function()
    require("neocoder").setup({
      provider = {
        adapter = "opencode", -- opencode | codex | claude | azure_openai
        fallback_adapters = { "codex", "claude" },
        model = "opencode/claude-sonnet-4-5",
      },
      safety = {
        mode = "read_only_first",
        autopilot_mode = "guarded", -- guarded | strict | aggressive
        dangerous_shell = "deny", -- deny | ask
        allow_safe_readonly_bash = true,
      },
      planner = {
        review_before_execute = false, -- set true to require plan approval
      },
    })
  end,
}

Approval scopes:

  • Once: allow this exact action once
  • Always (Session): remember as wildcard rule for current session
  • Always (Project): persist wildcard rule to .neocoder/policy.json

Azure OpenAI example:

require("neocoder").setup({
  provider = {
    adapter = "azure_openai",
    azure_openai = {
      endpoint = "https://YOUR_RESOURCE.openai.azure.com",
      deployment = "gpt-4.1",
      api_version = "2024-10-21",
      api_mode = "chat_completions", -- or "responses"
      api_key_env = "AZURE_OPENAI_API_KEY",
    },
  },
})

Provider fallback behavior:

  • NeoCoder tries provider.adapter first.
  • If it fails, it tries provider.fallback_adapters in order.
  • You can also provide per-request fallback via fallback_adapters.

Session runtime override behavior:

  • :NeocoderSwitchProvider sets a session-level provider adapter.
  • :NeocoderModel sets a session-level model override.
  • :NeocoderProvider displays configured vs active runtime adapter/model.

Daemon + Verification

NeoCoder can run a local daemon (scripts/neocoderd.py) to speed up scope decisions, indexed retrieval, and verification.

Requirements:

  • python3 available in PATH (or set daemon.python_cmd)

Example config:

require("neocoder").setup({
  daemon = {
    enabled = true,
    auto_start = true, -- auto-start on first daemon request
    start_on_setup = false, -- optional eager start in setup()
    host = "127.0.0.1",
    port = 45454,
    python_cmd = "python3",
    use_for_scope = true,
    auto_index = true,
    use_for_verification = true,
  },
  verification = {
    enabled = true,
    require_pass_for_success = true,
    fallback_to_local_on_daemon_error = true,
    auto_detect = true, -- package.json/Makefile detection when commands unset
    timeout_ms = 120000,
    commands = {
      build = nil,
      test = nil,
      lint = nil,
    },
  },
})

Runtime visibility:

  • :NeocoderStatus includes daemon state and last health/error details.
  • :NeocoderDoctor reports daemon script resolution/readability and verification config.
  • :NeocoderDaemon shows daemon process info and recent daemon logs.
  • :NeocoderDaemonStart, :NeocoderDaemonStop, :NeocoderDaemonReindex manage daemon lifecycle manually.
  • :NeocoderVerify runs verification on-demand outside a coding turn.
  • If daemon verification fails and verification.fallback_to_local_on_daemon_error = true, NeoCoder runs local verification as a fallback.

Commands

  • :NeocoderAsk [prompt]
  • :NeocoderSearch [prompt]
  • :NeocoderVisual [prompt]
  • :NeocoderHistory
  • :NeocoderToggle
  • :NeocoderChatNew
  • :NeocoderClear
  • :NeocoderCompact
  • :NeocoderResume <session_id>
  • :NeocoderFork [session_id]
  • :NeocoderCancel
  • :NeocoderStop
  • :NeocoderAcceptPatch
  • :NeocoderRejectPatch
  • :NeocoderStatus
  • :NeocoderScope
  • :NeocoderMCP
  • :NeocoderDoctor
  • :NeocoderTrace [turn_id]
  • :NeocoderTools [server_id]
  • :NeocoderSwitchProvider <adapter> [model]
  • :NeocoderModel <model>
  • :NeocoderProvider
  • :NeocoderModels
  • :NeocoderRepoMap
  • :NeocoderRagStatus
  • :NeocoderVerify
  • :NeocoderDaemonStart
  • :NeocoderDaemonStop
  • :NeocoderDaemonReindex
  • :NeocoderDaemon
  • :NeocoderACPStatus
  • :NeocoderPromptLog [limit]
  • :NeocoderReplayPrompt <log_id>

Adaptive Scope + Retrieval

Prompt tags to override scope:

  • @selection
  • @file
  • @module
  • @repo
  • @external
  • @local_only / @no_external

Prompt directive DSL:

  • Slash commands: /new, /clear, /compact, /lines <start>-<end> <question>, /commit, /provider <adapter>, /model <model>, /stop
  • Mentions: @file:<path> or @file <path>, @codebase, @diagnostics, @selection
  • Shortcuts: #refactor, #test
  • Tool policy controls: @disable_tool:<tool>, @enable_tool:<tool>, @approval:auto|ask|policy_default

Runtime behavior:

  • NeoCoder infers prompt scope and emits scope_decided.
  • NeoCoder computes an autonomy route and emits autonomy_decision.
  • Retrieval stages gather evidence before planning.
  • Retrieval includes repo-map symbols when enabled (retrieval.repo_map.enabled = true).
  • Optional RAG retrieval stage runs when confidence is still low and rag.enabled = true.
  • Evidence is ranked (weighted_v2) and deduped before planner ingestion.
  • Planner receives compact evidence summary, not full raw dumps.
  • Scope and retrieval traces are persisted in .neocoder/sessions/<id>/retrieval.json.
  • Retrieval v2 output is persisted in .neocoder/sessions/<id>/retrieval-v2.json.
  • Autonomy decisions are persisted in .neocoder/sessions/<id>/decisions.jsonl.

Tool Policy Precedence

When a tool step is evaluated, NeoCoder applies policy in this order:

  1. Turn directive (@enable_tool, @disable_tool, @approval:*)
  2. Session runtime overrides (:Neocoder* actions persisted in state)
  3. Provider adapter policy (provider.adapter_policies[adapter])
  4. Global tool policy (tools.auto_approve, tools.disabled_global)
  5. Safety defaults (safety.tool_policy.*)
  6. Tool manifest defaults (tool/manifest.lua + tools.manifest_overrides)

Example provider adapter policy:

require("neocoder").setup({
  provider = {
    adapter = "azure_openai",
    adapter_policies = {
      azure_openai = {
        approval_mode = "ask_all",
        disable_tools = { "bash" },
      },
    },
  },
})

Example global tool policy:

require("neocoder").setup({
  tools = {
    auto_approve = { "read_file", "grep", "diagnostics" },
    disabled_global = { "bash" },
    manifest_overrides = {
      rag_search = {
        requires_confirmation = true,
      },
    },
  },
})

MCP Integration

Current MCP layer includes:

  • Stdio JSON-RPC runtime (initialize/tools/list/tools/call)
  • Dynamic registry cache (.neocoder/mcp/registry-cache.json)
  • Project version pin lock (.neocoder/mcp/lock.json)
  • Install approval flow (install_policy = "ask_then_cache")
  • Runtime session pool + restart handling
  • Local MCP surf: filesystem + git
  • External MCP surf: github + fetch (auto when confidence is low)

Example config:

require("neocoder").setup({
  scope = {
    enabled = true,
    mode = "adaptive",
  },
  retrieval = {
    enabled = true,
    strategy = "balanced",
    ranker = "weighted_v2",
    dedupe = "path_symbol_hash",
    external_budget = {
      max_calls = 3,
      max_bytes = 180000,
    },
    repo_map = {
      enabled = true,
      max_files = 160,
      max_defs_per_file = 16,
    },
  },
  rag = {
    enabled = false,
    endpoint = "http://127.0.0.1:20250",
    auto_index = false,
  },
  acp = {
    enabled = false,
    follow_agent_locations = true,
    providers = {},
  },
  autonomy = {
    enabled = true,
    route_policy = "adaptive", -- adaptive | internal_only | external_first
    max_subtasks = 3,
    max_depth = 2,
    external_escalation_threshold = 0.74,
  },
  mcp = {
    enabled = true,
    protocol = "stdio_jsonrpc",
    registry_mode = "dynamic",
    install_policy = "ask_then_cache",
    external_policy = "auto_when_needed",
    session_pool_size = 4,
    server_ttl_ms = 300000,
    max_restarts = 3,
  },
})

Runtime event subscription

local neocoder = require("neocoder")
neocoder.on_event("event", function(ev)
  -- ev.type, ev.payload, ev.session_id, ev.turn_id
end)

Session lifecycle features

  • Session fork with history cloning (:NeocoderFork)
  • Turn checkpoints at start/finish under .neocoder/sessions/<id>/snapshots/
  • Usage tracking in .neocoder/sessions/<id>/usage.jsonl
  • MCP call traces in .neocoder/sessions/<id>/mcp-calls.jsonl
  • Prompt logs in .neocoder/sessions/<id>/prompt-log.jsonl

Persistence migration

  • NeoCoder runs schema migration during setup().
  • Current persistence schema version is written to .neocoder/schema-version.json.
  • Last migration report is written to .neocoder/migration-report.json.

Patch workflow v2

  • Hunk-aware patch object model (version = 2)
  • Diff review keys: a accept all, r reject all, h toggle current hunk, j/k jump hunk
  • Safe no-op behavior when all hunks are rejected

Planner hardening

  • Plan normalization enforces max-step budget and final step
  • Optional pre-execution plan review (planner.review_before_execute = true)

Default keymaps

  • <leader>nn ask
  • <leader>nv visual
  • <leader>ns search
  • <leader>nh history
  • <leader>nt toggle workspace
  • <leader>nc clear session
  • <leader>nC compact session
  • <leader>nx cancel
  • <leader>na accept patch
  • <leader>nr reject patch

Architecture docs

  • docs/architecture.html
  • architecture.html (redirects to docs page)
  • docs/execution-trace.html
  • docs/architecture.mmd

execution-trace.html now surfaces autonomy/retrieval/MCP lifecycle insights from:

  • .neocoder/sessions/<id>/events.jsonl
  • .neocoder/sessions/<id>/decisions.jsonl
  • .neocoder/sessions/<id>/mcp-calls.jsonl

Local validation

make test

Test matrix currently includes:

  • Unit checks: scope tags, autonomy decisions, protocol encode/parse, budget enforcement.
  • Integration checks: registry fallback behavior, install deny path, retrieval external escalation, lock finalize pin.
  • E2E checks: full neocoder.search() turn run with trace events (scope_decided, autonomy_decision, turn_done).

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages