bound-code
v0.1.1
Published
A bounded, budget-limited coding agent: local structural index + a capability-sandboxed planner/executor loop for small, well-scoped tasks.
Readme
bound-code
Bound — the bounded-context code engine for fast, low-cost PRs.
bound builds a local structural index of your repository once, then uses
it to plan and execute small, well-scoped tasks with a hard tool-call/turn
budget — instead of exploring the repository from scratch on every task.
It is not a general coding agent. It is the tool you reach for when the task
is small, the repo is known, and you don't want to spend a deep-exploration
budget (in tokens, latency, or trust) on a one-line fix. For anything bigger,
configure --fallback to hand off to a general agent you already use.
How it works
bound indexparses your repository into files, symbols, a call graph, an import graph, and test↔source links, and stores it in.bound/context.db(SQLite + FTS5). It makes no network call — cheap and deterministic, safe to run in CI or a pre-commit hook.bound run "<task>" --kind <kind>runs a read-only planner that searches the index (never the live filesystem) to select the smallest file cluster for the task, within a hard tool-call budget. It writes the change for real by default; pass--dry-runto see the plan without touching anything.- A sandboxed executor applies exact-match patches only within that cluster, runs the configured test command, and a third, source-free reviewer pass checks the diff against the task before accepting it.
- If the bounded path exhausts its budget, crosses
--max-tokens, or the result isn't accepted, and you configured--fallback=<command>, that command receives the task and runs instead — with a visible, explicit escalation message, never silently.
Language and framework support
Bound's local structural index currently parses TypeScript/JavaScript, Python, Go and PHP. Parsing a language is not the same promise as a framework mapping: the generic index uses symbols, imports, calls and conventional test-file links for every supported language; a mapping adds an opt-in, framework-specific structural relation only when it improves precision.
| Scope | Current status | What it means |
| --- | --- | --- |
| Go / Gin | Validated through the public go-chi/chi and Gin corpora | Generic Go indexing supports *_test.go; the narrow Gin mapping adds direct named-handler route facts. |
| Python / FastAPI | Validated with an opt-in fastapi mapping | Adds declarative route and test-HTTP relations. |
| TypeScript / NestJS | In calibration with an opt-in nest mapping | Adds declarative @Controller and HTTP-decorator relations. |
| PHP | Parser/index support | A public planning corpus is still required before claiming framework-level validation. |
Other libraries may already work through the generic path. For example, Gin uses Go source and conventional Go tests, but it is not yet corpus-validated and must not be treated as a supported framework promise. A new mapping should be proposed only when a reproducible corpus failure shows that a local, declarative AST relation improves planning accuracy; otherwise add the corpus first and retain the generic index.
Framework mappings are explicit: select one during indexing only when the
repository actually uses it, for example bound index --framework fastapi.
The files in frameworks/ define the audited mapping schema;
See contributing a framework mapping for the required fixtures, corpus baseline and security gate. The mapping file alone does not establish framework support.
See docs/OPERATING_GUIDE.md for BYOK, root/stack
selection, task kinds, fallback and suitability limits, and
docs/EXAMPLES.md for a real, corpus-backed worked
example per supported language.
Their absence means “generic indexing”, not “unsupported”.
Install
npm install -g bound-codeRequires Node.js >= 22.16 (uses the built-in node:sqlite, whose FTS5
support was only compiled in by default starting at that patch —
nodejs/node#57621).
Usage
cd your-project
bound index # build the local index (no network call)
bound run "Fix DTO validation error on user creation" --kind behavior # plans, then executes for real
bound run "Update payment webhook response" --kind source --dry-run # show the plan only
bound run "..." --kind test --max-tokens 8000 --fallback='claude -p {context}'
bound status # or: bound doctor
bound history
bound clean # wipe .bound/ (index + run history + cache)Library API
The same engine is available to Node.js consumers without invoking the CLI.
indexProject and runTask never print to the terminal or call
process.exit; callers receive a typed result and may render progress however
they choose.
import { indexProject, runTask } from "bound-code";
await indexProject({ root: process.cwd() });
const result = await runTask({
root: process.cwd(),
task: { task_id: "local-1", title: "Fix greeting", description: "Fix the greeting copy.", kind: "source" },
credentials: { provider: "openai", key: process.env.OPENAI_API_KEY! },
dryRun: true,
});
if (result.status === "accepted") console.log(result.changed_files);Possible statuses are planned, accepted, rejected, budget_exhausted
and error. A budget_exhausted result includes an escalation object with
the task, any completed plan, partial usage and tool-call trace. The caller
owns any fallback/escalation policy.
Caller-selected scope
Every public run supplies task.kind: test, documentation, behavior, or
source. The caller selects the project root, enabled framework mappings, and
this edit intent before Bound runs. Bound then verifies the selection against
the local index; it never expands a caller-selected scope. In particular,
behavior requires both the anchored source and directly supported test
evidence. If that evidence is absent or conflicts with the supplied kind,
Bound returns a bounded handoff instead of guessing from task wording.
Every terminal result includes telemetry.contract_version (currently 1),
with source-free planner, executor, review and focused-test evidence. The CLI
uses the same stable version marker in every bound run --json event as
schema_version: 1; progress stays on stderr and machine-readable events stay
on stdout. Breaking changes increment the relevant version.
bound run refuses to run against a dirty git working tree (pass --force
to override) — your git history is the undo button for whatever it writes.
Configuration
Credentials (BYOK)
bound reads the same standard per-provider environment variables other AI
CLIs use, checked in your real shell environment first, then in the
project's .env:
ANTHROPIC_API_KEY=...
DEEPSEEK_API_KEY=...
OPENAI_API_KEY=...
GEMINI_API_KEY=...If your shell already has one of these set for another tool, bound needs
no extra setup. If more than one is present, pick the active one explicitly:
bound config set provider deepseekAll four advertised providers implement the same mocked planner/executor tool session contract: OpenAI, DeepSeek, Gemini and Anthropic. DeepSeek Flash is the only current public-corpus BYOK baseline; choose another provider explicitly and treat it as a supported protocol path pending an equivalent live corpus baseline. Provider calls have bounded timeouts and return usage when their API reports it; missing cache data stays absent rather than being guessed.
bound run will prompt interactively and save the key to .env if none of
these resolve and you're in a terminal.
Preferences
Non-secret preferences live in .bound.json (project) or
~/.config/bound/config.json (global, via --global) — never API keys:
bound config set default_max_tokens 12000
bound config set preferred_model deepseek-chat
bound config set fallback "claude -p {context}"
bound config listCommands
CORE COMMANDS:
index Builds or refreshes the local SQLite symbol graph
run <task> Executes a bounded task; requires --kind
history Displays history of past runs, token usage, and outcomes
UTILITIES:
status (doctor) Checks index freshness, API keys, and environment health
config get|set|unset|list Gets or sets local/global configuration defaults
clean Clears the local .bound context database and caches--fallback
--fallback=<command> is a generic escalation hatch, not tied to any one
vendor. It only fires on a deterministic signal (budget exhausted,
--max-tokens crossed, or the result wasn't accepted) and only when you've
explicitly configured it, via the flag or bound config set fallback.
The command runs directly through spawn, never a shell. It must contain at
least one placeholder:
bound run "..." --kind source --fallback='claude -p {context}'
bound run "..." --kind source --fallback='my-agent --input {context_file}'
bound run "..." --kind source --fallback='my-agent --task {task} --evidence {context_file}'{context} is the full JSON handoff as one argv value. {context_file} is a
mode-600 JSON file in .bound/, useful for large prompts or tools that read an
input file. {task} is the raw task description. The handoff includes the
bounded plan/evidence, token usage and any partial changed files so the next
tool can continue rather than rediscovering the repository from zero.
Fallback handoffs use version: 1. It is an argv-only boundary — Bound never
selects or launches a fallback unless the caller explicitly configured one.
Quality gates
Contributors can run the complete offline regression gate with:
npm run test:regressionIt type-checks the engine, enforces coverage, indexes versioned fixtures for TypeScript/JavaScript, Python, Go and PHP, and validates both the CLI and the packed npm artifact in clean temporary repositories. It does not use provider credentials or make network calls. See CI and regression gates for the distinction between this per-PR gate and the explicit BYOK external corpus calibration.
Status
Early. This is an extraction of a harness developed inside another project;
the index format and CLI surface may still change — see
CHANGELOG.md for what that means for 0.x
releases specifically.
More
CHANGELOG.md— what shipped in each release.docs/EXAMPLES.md— a real worked example per supported language.CONTRIBUTING.md— issue policy, support criteria, how to run the checks.SECURITY.md— how to report a vulnerability.docs/JOURNAL.md— the full build log and the reasoning behind non-obvious decisions.
License
MIT
