The core loop is genuinely reachable: open-source agents already route across model families, run tools, and edit repos, and a weekend of wiring gets you a personal version. What does not fall out of a weekend is the harness around the model, which is where AdaL claims its numbers come from, plus browser-based verification, clustered code review, and the team controls. You end up with an agent that works and a noticeably worse recovery rate on long tasks.
You are building a lean indie version of AdaL. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== README.md ===== # AdaL · indie build A terminal coding agent whose hard problems are not the model calls but the harness around them: tools that cannot leak a secret or escape the repository, sessions that resume after a crash mid-tool-call, delegation that gives each sub-agent only what it needs, and a verification loop the agent cannot satisfy by weakening the tests. Estimated effort: **weekend**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | Python 3.12, one file per module, no framework | the harness is the product and every layer between you and it hides behaviour | | Providers | Anthropic, OpenAI and Google behind one chat(model, messages, tools) function | a fourth provider is one file, and switching mid-session is a flag | | Tools | read_file, write_file, list_dir, run_shell and run_tests, confined to the repository | the agent's reach is exactly this list, and the list is short on purpose | | Sessions | Append-only JSONL under .agent/sessions with every call, result and cost | replay and resume need the events, not a summary of them | | Verification | The project's own test command after every edit, with a shown diff of any test change | passing by weakening a test is the failure that looks like success | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Python 3.12 or newer** · free - Why: Runs the agent, its tools and the test suite. - Get it: python.org or your package manager. - Verify: python3 --version prints 3.12 or higher - [ ] **API keys for at least two providers** · per token, and a long task can be several pounds - Why: Routing across model families is the point, and a single provider hides every seam the design depends on. - Get it: Per-token billing accounts with two of Anthropic, OpenAI and Google, keys in .env, and note the current published prices for the price file. - Verify: chat() returns from both providers and the recorded cost matches the price file - [ ] **A repository with a real test suite** · free - Why: The verification loop is only meaningful against tests that can actually fail, and a toy project with one passing test exercises none of it. - Get it: A project of your own with at least fifty tests and a configured test command. - Verify: The test command runs from the project's configuration and at least one test can be made to fail - [ ] **Two fixtures for the verification loop** · free - Why: One where the implementation is wrong and the test is right, and one where the only way to go green is to weaken the test, are the two cases the loop must tell apart. - Get it: Write both by hand in the repository's test style. - Verify: The first ends fixed and the second ends stopped with the diff shown - [ ] **A dated price file and your ceilings** · free - Why: Cost is computed from it and a ceiling is derived from it, and a number remembered from a blog post is wrong more often than not. - Get it: Copy each provider's current published prices per million tokens into prices.json with the date checked, and decide a per-session and a daily ceiling. - Verify: prices.json has a checked_on date within the last month and both ceilings are set ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - Browser-based verification of a running application. - A graphical interface. - Team accounts and organisation controls. - Any hosted service. - harness tuning: the planning, recovery and verification work that separates a demo agent from one that finishes long tasks - browser-use verification of the app you just changed - review clustering that groups a large diff into risk-ranked units - one bill across every frontier provider instead of six metered API accounts - SSO, SAML/SCIM, zero data retention and org-level model deny lists If one of those is essential to you, that is the reason to keep paying for AdaL, and the README should say so rather than pretend. ===== BRIEF.md ===== # Build brief · AdaL The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a coding agent for the terminal that plans, delegates to fresh sub-agents, and shows you every command before it runs to replace AdaL. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Runtime: Python 3.12, one file per module, no framework · the harness is the product and every layer between you and it hides behaviour - Providers: Anthropic, OpenAI and Google behind one chat(model, messages, tools) function · a fourth provider is one file, and switching mid-session is a flag - Tools: read_file, write_file, list_dir, run_shell and run_tests, confined to the repository · the agent's reach is exactly this list, and the list is short on purpose - Sessions: Append-only JSONL under .agent/sessions with every call, result and cost · replay and resume need the events, not a summary of them - Verification: The project's own test command after every edit, with a shown diff of any test change · passing by weakening a test is the failure that looks like success ### Data model (create this before Phase 1) - sessions/<id>.jsonl · one event per line: kind, at, step, role, content, tool, args, result, tokens_in, tokens_out, cost_minor, model - plan(step_n, description, acceptance_command, tools_allowed, state, attempts) · written by the planner, run one step per sub-agent - scratchpad.md · the shared record sub-agents append to, and the only context a later sub-agent inherits - approvals(at, command, cwd, decision, session_id) · every shell command shown, and what you said - denied_paths · .env, keys, credentials and anything matching your patterns, refused by read_file before the model sees a byte - prices.json(provider, model, input_per_million, output_per_million, checked_on) · maintained by you from the providers' published prices, dated, never assumed - A tool call and its result are two events, so a crash between them shows on resume as a call with no result rather than as a call that never happened. ### Phase 1 · Tools that cannot reach what they should not Build: Implement chat() over the three providers with keys from .env, a --model flag that switches mid-session, and the five tools. Confine every path to the repository after resolving symlinks. Refuse reads of denied files and redact secret-shaped strings from tool output before it reaches the model. run_shell prints the command and waits for y or n unless --yolo was passed. Trap: The first thing a model does in an unfamiliar repository is read the configuration, and .env is configuration, so within minutes your provider keys are in a prompt on somebody else's server and in your own session log. Deny the files by name and pattern inside read_file, redact key-shaped strings from every tool result, and test both with a planted fake key. Done when: A read of .env or of a file matching a denied pattern is refused with a message the model can act on, tested. A write to a path outside the repository, including through a symlink, is refused. A planted fake key in a file the agent may read is redacted from the tool result and never appears in the session log, asserted by searching the log. A shell command runs only after y, and --yolo is the only way around it. Do not build yet: No sessions, planner, sub-agents, verification loop or cost reporting. ### Phase 2 · Sessions that resume after the worst moment Build: Append every message, tool call, tool result and usage figure to a JSONL file as it happens, flushing per line. Implement --resume to reload the events and the scratchpad and continue from the last complete step, treating a call with no result as not done. Print tokens and cost per provider at the end of every turn, computed from the dated price file. Trap: Writing the session to disk at the end of the run means the run that crashed after forty minutes of work leaves nothing, and the one that crashes is always that one. Append and flush per event, and on resume treat a tool call without a result as never having happened, because you cannot know whether it did. Done when: Killing the process between a tool call and its result leaves a log from which resume reports the incomplete call and re-asks rather than assuming. Replaying a session reproduces the same sequence of events and the same totals. Cost per provider is printed per turn and equals the recorded tokens times the price file, unit tested. A price file older than a stated number of days prints a warning that the figures may be stale. Do not build yet: No planner, sub-agents or verification loop yet. ### Phase 3 · A planner whose steps can be checked Build: A planner call produces numbered steps, each with a description, an acceptance command and the tools it may use. Each step runs as a sub-agent with a fresh context containing the step, the scratchpad and the files it names, and nothing else. The sub-agent appends its result to the scratchpad. A step whose acceptance command fails retries once, then the run stops and reports. Trap: Handing each sub-agent the entire conversation so far defeats the reason for splitting the work, costs a full context per step, and lets step six get confused by step two's abandoned approach. Give it the step, the scratchpad and the named files, and make the planner produce steps you can refuse when an acceptance command is missing or amounts to 'looks good'. Done when: A plan containing a step without an acceptance command is rejected and the planner is re-asked, tested with a fixture plan. Each sub-agent's context contains only the step, the scratchpad and the named files, asserted by inspecting the messages sent. A step failing acceptance twice stops the run with the failing output shown. A sub-agent cannot use a tool outside its step's list, tested by a step that tries. Do not build yet: No automatic test loop or cost ceilings yet. ### Phase 4 · Verification the agent cannot game Build: After any step that edits files, run the project's test command and feed failures back to the same sub-agent for one retry. Detect any change to test files during a retry, show the diff, and require approval before accepting it. Refuse a retry that deletes or skips tests. Keep a summary of what changed per step for the final report. Trap: Given a failing test and permission to edit, a model will sometimes loosen the assertion, mark the test as skipped or delete the file, and the run then reports success with the tests green. Diff the test files after every retry, show the diff, and treat a retry whose only change is to the tests as a failure that needs a human. Done when: A fixture where the implementation is wrong and the test is right ends with a working implementation. A fixture where the only way to go green is to weaken the test ends with a stop and the test diff shown, not a pass. A skipped or deleted test during a retry is refused. The final report lists the files changed per step with the acceptance result. Do not build yet: No cost ceilings, fourth provider or the honest comparison yet. ### Phase 5 · Ceilings, a fourth provider, and where this loses Build: A per-session cost ceiling that stops the run before the next call would exceed it, and a daily ceiling in the price file. Document adding a fourth provider as a single module with the same function shape, and add a fake one in the suite. Write the README section on where this loses to a commercial harness on long tasks: recovery, verification depth and browser checks. Trap: A ceiling checked after the call has already been made is a bill with a warning attached, and on a long planning step with a large context a single call can be most of the budget. Estimate the next call from the context size and refuse before making it, and make the refusal say what it would have cost. Done when: A run stops before the call that would exceed the ceiling, with the estimate shown, tested with a small ceiling. A fake fourth provider is added as one module and works in every code path, asserted in the suite. The README states plainly which parts of a commercial harness this does not have. The session log exports to plain Markdown for reading later. Do not build yet: Nothing after this. ### Out of scope (and why) - Browser automation to verify a running application, which is a second agent with its own failure modes and is part of where the subscription's recovery rate comes from. - A graphical interface, since the terminal is where the approvals, diffs and costs are already readable. - Team accounts, shared sessions and organisation-level model controls, which are the compliance surface companies pay for and a solo developer does not need. - Any hosted service, because the point of this build is that the keys, the code and the session log stay on your machine. ### README must contain - That secret files are denied and key-shaped strings are redacted before the model sees a tool result, tested with a planted key - That every shell command is shown and waits for approval unless --yolo was passed - That sessions are append-only JSONL flushed per event, and resume treats a call without a result as never made - That each sub-agent gets only its step, the scratchpad and the named files, and every step has an acceptance command - That a retry which weakens, skips or deletes a test stops the run rather than passing it - That cost comes from a dated price file you maintain, and a ceiling refuses before the call rather than after ===== AGENTS.md ===== # Agent instructions · AdaL indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: Python 3.12, one file per module, no framework, Anthropic, OpenAI and Google behind one chat(model, messages, tools) function, read_file, write_file, list_dir, run_shell and run_tests, confined to the repository, Append-only JSONL under .agent/sessions with every call, result and cost, The project's own test command after every edit, with a shown diff of any test change. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - The first thing a model does in an unfamiliar repository is read the configuration, and .env is configuration, so within minutes your provider keys are in a prompt on somebody else's server and in your own session log. Deny the files by name and pattern inside read_file, redact key-shaped strings from every tool result, and test both with a planted fake key. - Writing the session to disk at the end of the run means the run that crashed after forty minutes of work leaves nothing, and the one that crashes is always that one. Append and flush per event, and on resume treat a tool call without a result as never having happened, because you cannot know whether it did. - Handing each sub-agent the entire conversation so far defeats the reason for splitting the work, costs a full context per step, and lets step six get confused by step two's abandoned approach. Give it the step, the scratchpad and the named files, and make the planner produce steps you can refuse when an acceptance command is missing or amounts to 'looks good'. - Given a failing test and permission to edit, a model will sometimes loosen the assertion, mark the test as skipped or delete the file, and the run then reports success with the tests green. Diff the test files after every retry, show the diff, and treat a retry whose only change is to the tests as a failure that needs a human. ===== BUILD_PLAN.md ===== # Build plan · AdaL A terminal coding agent whose hard problems are not the model calls but the harness around them: tools that cannot leak a secret or escape the repository, sessions that resume after a crash mid-tool-call, delegation that gives each sub-agent only what it needs, and a verification loop the agent cannot satisfy by weakening the tests. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · Tools that cannot reach what they should not The agent reads, writes and runs inside the repository and nowhere else, and never sees a secret. ### Steps 1. Put the providers behind one function Keys from .env, model switch by flag, no provider code anywhere else. Files: `providers.py`, `config.py` 2. Confine paths and deny secrets before the model sees them Resolve symlinks first; test with a planted fake key. Files: `tools.py`, `redact.py`, `tests/test_secrets.py` 3. Show every shell command and wait Print it, wait for y or n, record the answer. Files: `shell.py`, `approvals.py` ### Done when - [ ] Denied files are refused with an actionable message - [ ] Writes outside the repository are refused, symlinks included - [ ] A planted key never reaches the log or the model - [ ] Shell commands wait for approval unless --yolo ### Watch out - The first thing a model does in an unfamiliar repository is read the configuration, and .env is configuration, so within minutes your provider keys are in a prompt on somebody else's server and in your own session log. Deny the files by name and pattern inside read_file, redact key-shaped strings from every tool result, and test both with a planted fake key. ## Phase 2 · Sessions that resume after the worst moment A crash mid-tool-call is visible and recoverable, and every turn's cost is known. ### Steps 1. Append and flush per event The crash that matters is the one after forty minutes. Files: `session.py` 2. Resume from the last complete step A call without a result did not happen, as far as you can know. Files: `resume.py`, `tests/test_resume.py` 3. Price from a dated file, warn when stale Never a number in code; you maintain the file and its date from the published prices. Files: `cost.py`, `prices.json` ### Done when - [ ] A kill mid-call is reported as incomplete on resume - [ ] Replay reproduces the events and totals - [ ] Per-turn cost equals tokens times the price file - [ ] A stale price file warns ### Watch out - Writing the session to disk at the end of the run means the run that crashed after forty minutes of work leaves nothing, and the one that crashes is always that one. Append and flush per event, and on resume treat a tool call without a result as never having happened, because you cannot know whether it did. ## Phase 3 · A planner whose steps can be checked Work is split into steps that each state how you would know they are done, and each runs in a fresh context. ### Steps 1. Require an acceptance command per step A step that cannot fail cannot succeed either. Files: `planner.py`, `tests/test_plan_shape.py` 2. Give each sub-agent a fresh, narrow context The step, the scratchpad, the named files. Assert it. Files: `subagent.py`, `tests/test_context.py` 3. Retry once, then stop and report An agent that retries forever is spending your money on the same mistake. Files: `orchestrator.py` ### Done when - [ ] Steps without acceptance commands are rejected - [ ] Sub-agent context is exactly the step, scratchpad and named files - [ ] Two acceptance failures stop the run with output shown - [ ] Out-of-list tools are refused per step ### Watch out - Handing each sub-agent the entire conversation so far defeats the reason for splitting the work, costs a full context per step, and lets step six get confused by step two's abandoned approach. Give it the step, the scratchpad and the named files, and make the planner produce steps you can refuse when an acceptance command is missing or amounts to 'looks good'. ## Phase 4 · Verification the agent cannot game Edits are tested automatically, and the only way to pass is to make the code work. ### Steps 1. Run the tests after every edit From the project's own configuration, not a guess at the command. Files: `verify.py` 2. Diff test files after a retry and require approval A loosened assertion is the pass that is not a pass. Files: `verify.py`, `tests/test_no_test_weakening.py` 3. Summarise changes per step So the final report is what happened rather than what was planned. Files: `report.py` ### Done when - [ ] A wrong implementation with a right test ends fixed - [ ] A test-weakening retry stops with the diff shown - [ ] Skipped or deleted tests are refused - [ ] The report lists changes per step with results ### Watch out - Given a failing test and permission to edit, a model will sometimes loosen the assertion, mark the test as skipped or delete the file, and the run then reports success with the tests green. Diff the test files after every retry, show the diff, and treat a retry whose only change is to the tests as a failure that needs a human. ## Not in this build - Browser-based verification of a running application. - A graphical interface. - Team accounts and organisation controls. - Any hosted service. ## After v1, if you want it - A read-only exploration mode for an unfamiliar repository at a fraction of the cost - Parallel sub-agents for independent steps, once the scratchpad has locking - A local model as a provider for the cheap steps, which the one-function seam already allows ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Optional · secret. One of at least two providers. Never read by the agent's own tools. ANTHROPIC_API_KEY=sk-ant-...redacted # Optional · secret. One of at least two providers. Never read by the agent's own tools. OPENAI_API_KEY=sk-...redacted # Optional · secret. One of at least two providers. Never read by the agent's own tools. GOOGLE_API_KEY=AIza...redacted # Required. Overridden per session by --model. Provider prefix selects the module. AGENT_DEFAULT_MODEL=anthropic:claude-sonnet-4-5 # Required. Append-only JSONL, flushed per event. Add it to .gitignore. SESSION_DIR=.agent/sessions # Required. Refused by read_file before the model sees a byte. Err wide. DENIED_PATTERNS=.env,*.pem,*.key,**/credentials* # Required. The run refuses the call that would exceed it, before making it. SESSION_COST_CEILING_MINOR=500 # Required. Your dated copy of the published prices. Stale beyond a month warns. PRICES_PATH=./prices.json
You are building a lean indie version of AdaL. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== README.md ===== # AdaL · indie build A terminal coding agent whose hard problems are not the model calls but the harness around them: tools that cannot leak a secret or escape the repository, sessions that resume after a crash mid-tool-call, delegation that gives each sub-agent only what it needs, and a verification loop the agent cannot satisfy by weakening the tests. Estimated effort: **weekend**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | Python 3.12, one file per module, no framework | the harness is the product and every layer between you and it hides behaviour | | Providers | Anthropic, OpenAI and Google behind one chat(model, messages, tools) function | a fourth provider is one file, and switching mid-session is a flag | | Tools | read_file, write_file, list_dir, run_shell and run_tests, confined to the repository | the agent's reach is exactly this list, and the list is short on purpose | | Sessions | Append-only JSONL under .agent/sessions with every call, result and cost | replay and resume need the events, not a summary of them | | Verification | The project's own test command after every edit, with a shown diff of any test change | passing by weakening a test is the failure that looks like success | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Python 3.12 or newer** · free - Why: Runs the agent, its tools and the test suite. - Get it: python.org or your package manager. - Verify: python3 --version prints 3.12 or higher - [ ] **API keys for at least two providers** · per token, and a long task can be several pounds - Why: Routing across model families is the point, and a single provider hides every seam the design depends on. - Get it: Per-token billing accounts with two of Anthropic, OpenAI and Google, keys in .env, and note the current published prices for the price file. - Verify: chat() returns from both providers and the recorded cost matches the price file - [ ] **A repository with a real test suite** · free - Why: The verification loop is only meaningful against tests that can actually fail, and a toy project with one passing test exercises none of it. - Get it: A project of your own with at least fifty tests and a configured test command. - Verify: The test command runs from the project's configuration and at least one test can be made to fail - [ ] **Two fixtures for the verification loop** · free - Why: One where the implementation is wrong and the test is right, and one where the only way to go green is to weaken the test, are the two cases the loop must tell apart. - Get it: Write both by hand in the repository's test style. - Verify: The first ends fixed and the second ends stopped with the diff shown - [ ] **A dated price file and your ceilings** · free - Why: Cost is computed from it and a ceiling is derived from it, and a number remembered from a blog post is wrong more often than not. - Get it: Copy each provider's current published prices per million tokens into prices.json with the date checked, and decide a per-session and a daily ceiling. - Verify: prices.json has a checked_on date within the last month and both ceilings are set ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - Browser-based verification of a running application. - A graphical interface. - Team accounts and organisation controls. - Any hosted service. - harness tuning: the planning, recovery and verification work that separates a demo agent from one that finishes long tasks - browser-use verification of the app you just changed - review clustering that groups a large diff into risk-ranked units - one bill across every frontier provider instead of six metered API accounts - SSO, SAML/SCIM, zero data retention and org-level model deny lists If one of those is essential to you, that is the reason to keep paying for AdaL, and the README should say so rather than pretend. ===== BRIEF.md ===== # Build brief · AdaL The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a coding agent for the terminal that plans, delegates to fresh sub-agents, and shows you every command before it runs to replace AdaL. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Runtime: Python 3.12, one file per module, no framework · the harness is the product and every layer between you and it hides behaviour - Providers: Anthropic, OpenAI and Google behind one chat(model, messages, tools) function · a fourth provider is one file, and switching mid-session is a flag - Tools: read_file, write_file, list_dir, run_shell and run_tests, confined to the repository · the agent's reach is exactly this list, and the list is short on purpose - Sessions: Append-only JSONL under .agent/sessions with every call, result and cost · replay and resume need the events, not a summary of them - Verification: The project's own test command after every edit, with a shown diff of any test change · passing by weakening a test is the failure that looks like success ### Data model (create this before Phase 1) - sessions/<id>.jsonl · one event per line: kind, at, step, role, content, tool, args, result, tokens_in, tokens_out, cost_minor, model - plan(step_n, description, acceptance_command, tools_allowed, state, attempts) · written by the planner, run one step per sub-agent - scratchpad.md · the shared record sub-agents append to, and the only context a later sub-agent inherits - approvals(at, command, cwd, decision, session_id) · every shell command shown, and what you said - denied_paths · .env, keys, credentials and anything matching your patterns, refused by read_file before the model sees a byte - prices.json(provider, model, input_per_million, output_per_million, checked_on) · maintained by you from the providers' published prices, dated, never assumed - A tool call and its result are two events, so a crash between them shows on resume as a call with no result rather than as a call that never happened. ### Phase 1 · Tools that cannot reach what they should not Build: Implement chat() over the three providers with keys from .env, a --model flag that switches mid-session, and the five tools. Confine every path to the repository after resolving symlinks. Refuse reads of denied files and redact secret-shaped strings from tool output before it reaches the model. run_shell prints the command and waits for y or n unless --yolo was passed. Trap: The first thing a model does in an unfamiliar repository is read the configuration, and .env is configuration, so within minutes your provider keys are in a prompt on somebody else's server and in your own session log. Deny the files by name and pattern inside read_file, redact key-shaped strings from every tool result, and test both with a planted fake key. Done when: A read of .env or of a file matching a denied pattern is refused with a message the model can act on, tested. A write to a path outside the repository, including through a symlink, is refused. A planted fake key in a file the agent may read is redacted from the tool result and never appears in the session log, asserted by searching the log. A shell command runs only after y, and --yolo is the only way around it. Do not build yet: No sessions, planner, sub-agents, verification loop or cost reporting. ### Phase 2 · Sessions that resume after the worst moment Build: Append every message, tool call, tool result and usage figure to a JSONL file as it happens, flushing per line. Implement --resume to reload the events and the scratchpad and continue from the last complete step, treating a call with no result as not done. Print tokens and cost per provider at the end of every turn, computed from the dated price file. Trap: Writing the session to disk at the end of the run means the run that crashed after forty minutes of work leaves nothing, and the one that crashes is always that one. Append and flush per event, and on resume treat a tool call without a result as never having happened, because you cannot know whether it did. Done when: Killing the process between a tool call and its result leaves a log from which resume reports the incomplete call and re-asks rather than assuming. Replaying a session reproduces the same sequence of events and the same totals. Cost per provider is printed per turn and equals the recorded tokens times the price file, unit tested. A price file older than a stated number of days prints a warning that the figures may be stale. Do not build yet: No planner, sub-agents or verification loop yet. ### Phase 3 · A planner whose steps can be checked Build: A planner call produces numbered steps, each with a description, an acceptance command and the tools it may use. Each step runs as a sub-agent with a fresh context containing the step, the scratchpad and the files it names, and nothing else. The sub-agent appends its result to the scratchpad. A step whose acceptance command fails retries once, then the run stops and reports. Trap: Handing each sub-agent the entire conversation so far defeats the reason for splitting the work, costs a full context per step, and lets step six get confused by step two's abandoned approach. Give it the step, the scratchpad and the named files, and make the planner produce steps you can refuse when an acceptance command is missing or amounts to 'looks good'. Done when: A plan containing a step without an acceptance command is rejected and the planner is re-asked, tested with a fixture plan. Each sub-agent's context contains only the step, the scratchpad and the named files, asserted by inspecting the messages sent. A step failing acceptance twice stops the run with the failing output shown. A sub-agent cannot use a tool outside its step's list, tested by a step that tries. Do not build yet: No automatic test loop or cost ceilings yet. ### Phase 4 · Verification the agent cannot game Build: After any step that edits files, run the project's test command and feed failures back to the same sub-agent for one retry. Detect any change to test files during a retry, show the diff, and require approval before accepting it. Refuse a retry that deletes or skips tests. Keep a summary of what changed per step for the final report. Trap: Given a failing test and permission to edit, a model will sometimes loosen the assertion, mark the test as skipped or delete the file, and the run then reports success with the tests green. Diff the test files after every retry, show the diff, and treat a retry whose only change is to the tests as a failure that needs a human. Done when: A fixture where the implementation is wrong and the test is right ends with a working implementation. A fixture where the only way to go green is to weaken the test ends with a stop and the test diff shown, not a pass. A skipped or deleted test during a retry is refused. The final report lists the files changed per step with the acceptance result. Do not build yet: No cost ceilings, fourth provider or the honest comparison yet. ### Phase 5 · Ceilings, a fourth provider, and where this loses Build: A per-session cost ceiling that stops the run before the next call would exceed it, and a daily ceiling in the price file. Document adding a fourth provider as a single module with the same function shape, and add a fake one in the suite. Write the README section on where this loses to a commercial harness on long tasks: recovery, verification depth and browser checks. Trap: A ceiling checked after the call has already been made is a bill with a warning attached, and on a long planning step with a large context a single call can be most of the budget. Estimate the next call from the context size and refuse before making it, and make the refusal say what it would have cost. Done when: A run stops before the call that would exceed the ceiling, with the estimate shown, tested with a small ceiling. A fake fourth provider is added as one module and works in every code path, asserted in the suite. The README states plainly which parts of a commercial harness this does not have. The session log exports to plain Markdown for reading later. Do not build yet: Nothing after this. ### Out of scope (and why) - Browser automation to verify a running application, which is a second agent with its own failure modes and is part of where the subscription's recovery rate comes from. - A graphical interface, since the terminal is where the approvals, diffs and costs are already readable. - Team accounts, shared sessions and organisation-level model controls, which are the compliance surface companies pay for and a solo developer does not need. - Any hosted service, because the point of this build is that the keys, the code and the session log stay on your machine. ### README must contain - That secret files are denied and key-shaped strings are redacted before the model sees a tool result, tested with a planted key - That every shell command is shown and waits for approval unless --yolo was passed - That sessions are append-only JSONL flushed per event, and resume treats a call without a result as never made - That each sub-agent gets only its step, the scratchpad and the named files, and every step has an acceptance command - That a retry which weakens, skips or deletes a test stops the run rather than passing it - That cost comes from a dated price file you maintain, and a ceiling refuses before the call rather than after ===== AGENTS.md ===== # Agent instructions · AdaL indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: Python 3.12, one file per module, no framework, Anthropic, OpenAI and Google behind one chat(model, messages, tools) function, read_file, write_file, list_dir, run_shell and run_tests, confined to the repository, Append-only JSONL under .agent/sessions with every call, result and cost, The project's own test command after every edit, with a shown diff of any test change. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - The first thing a model does in an unfamiliar repository is read the configuration, and .env is configuration, so within minutes your provider keys are in a prompt on somebody else's server and in your own session log. Deny the files by name and pattern inside read_file, redact key-shaped strings from every tool result, and test both with a planted fake key. - Writing the session to disk at the end of the run means the run that crashed after forty minutes of work leaves nothing, and the one that crashes is always that one. Append and flush per event, and on resume treat a tool call without a result as never having happened, because you cannot know whether it did. - Handing each sub-agent the entire conversation so far defeats the reason for splitting the work, costs a full context per step, and lets step six get confused by step two's abandoned approach. Give it the step, the scratchpad and the named files, and make the planner produce steps you can refuse when an acceptance command is missing or amounts to 'looks good'. - Given a failing test and permission to edit, a model will sometimes loosen the assertion, mark the test as skipped or delete the file, and the run then reports success with the tests green. Diff the test files after every retry, show the diff, and treat a retry whose only change is to the tests as a failure that needs a human. ===== BUILD_PLAN.md ===== # Build plan · AdaL A terminal coding agent whose hard problems are not the model calls but the harness around them: tools that cannot leak a secret or escape the repository, sessions that resume after a crash mid-tool-call, delegation that gives each sub-agent only what it needs, and a verification loop the agent cannot satisfy by weakening the tests. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · Tools that cannot reach what they should not The agent reads, writes and runs inside the repository and nowhere else, and never sees a secret. ### Steps 1. Put the providers behind one function Keys from .env, model switch by flag, no provider code anywhere else. Files: `providers.py`, `config.py` 2. Confine paths and deny secrets before the model sees them Resolve symlinks first; test with a planted fake key. Files: `tools.py`, `redact.py`, `tests/test_secrets.py` 3. Show every shell command and wait Print it, wait for y or n, record the answer. Files: `shell.py`, `approvals.py` ### Done when - [ ] Denied files are refused with an actionable message - [ ] Writes outside the repository are refused, symlinks included - [ ] A planted key never reaches the log or the model - [ ] Shell commands wait for approval unless --yolo ### Watch out - The first thing a model does in an unfamiliar repository is read the configuration, and .env is configuration, so within minutes your provider keys are in a prompt on somebody else's server and in your own session log. Deny the files by name and pattern inside read_file, redact key-shaped strings from every tool result, and test both with a planted fake key. ## Phase 2 · Sessions that resume after the worst moment A crash mid-tool-call is visible and recoverable, and every turn's cost is known. ### Steps 1. Append and flush per event The crash that matters is the one after forty minutes. Files: `session.py` 2. Resume from the last complete step A call without a result did not happen, as far as you can know. Files: `resume.py`, `tests/test_resume.py` 3. Price from a dated file, warn when stale Never a number in code; you maintain the file and its date from the published prices. Files: `cost.py`, `prices.json` ### Done when - [ ] A kill mid-call is reported as incomplete on resume - [ ] Replay reproduces the events and totals - [ ] Per-turn cost equals tokens times the price file - [ ] A stale price file warns ### Watch out - Writing the session to disk at the end of the run means the run that crashed after forty minutes of work leaves nothing, and the one that crashes is always that one. Append and flush per event, and on resume treat a tool call without a result as never having happened, because you cannot know whether it did. ## Phase 3 · A planner whose steps can be checked Work is split into steps that each state how you would know they are done, and each runs in a fresh context. ### Steps 1. Require an acceptance command per step A step that cannot fail cannot succeed either. Files: `planner.py`, `tests/test_plan_shape.py` 2. Give each sub-agent a fresh, narrow context The step, the scratchpad, the named files. Assert it. Files: `subagent.py`, `tests/test_context.py` 3. Retry once, then stop and report An agent that retries forever is spending your money on the same mistake. Files: `orchestrator.py` ### Done when - [ ] Steps without acceptance commands are rejected - [ ] Sub-agent context is exactly the step, scratchpad and named files - [ ] Two acceptance failures stop the run with output shown - [ ] Out-of-list tools are refused per step ### Watch out - Handing each sub-agent the entire conversation so far defeats the reason for splitting the work, costs a full context per step, and lets step six get confused by step two's abandoned approach. Give it the step, the scratchpad and the named files, and make the planner produce steps you can refuse when an acceptance command is missing or amounts to 'looks good'. ## Phase 4 · Verification the agent cannot game Edits are tested automatically, and the only way to pass is to make the code work. ### Steps 1. Run the tests after every edit From the project's own configuration, not a guess at the command. Files: `verify.py` 2. Diff test files after a retry and require approval A loosened assertion is the pass that is not a pass. Files: `verify.py`, `tests/test_no_test_weakening.py` 3. Summarise changes per step So the final report is what happened rather than what was planned. Files: `report.py` ### Done when - [ ] A wrong implementation with a right test ends fixed - [ ] A test-weakening retry stops with the diff shown - [ ] Skipped or deleted tests are refused - [ ] The report lists changes per step with results ### Watch out - Given a failing test and permission to edit, a model will sometimes loosen the assertion, mark the test as skipped or delete the file, and the run then reports success with the tests green. Diff the test files after every retry, show the diff, and treat a retry whose only change is to the tests as a failure that needs a human. ## Not in this build - Browser-based verification of a running application. - A graphical interface. - Team accounts and organisation controls. - Any hosted service. ## After v1, if you want it - A read-only exploration mode for an unfamiliar repository at a fraction of the cost - Parallel sub-agents for independent steps, once the scratchpad has locking - A local model as a provider for the cheap steps, which the one-function seam already allows ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Optional · secret. One of at least two providers. Never read by the agent's own tools. ANTHROPIC_API_KEY=sk-ant-...redacted # Optional · secret. One of at least two providers. Never read by the agent's own tools. OPENAI_API_KEY=sk-...redacted # Optional · secret. One of at least two providers. Never read by the agent's own tools. GOOGLE_API_KEY=AIza...redacted # Required. Overridden per session by --model. Provider prefix selects the module. AGENT_DEFAULT_MODEL=anthropic:claude-sonnet-4-5 # Required. Append-only JSONL, flushed per event. Add it to .gitignore. SESSION_DIR=.agent/sessions # Required. Refused by read_file before the model sees a byte. Err wide. DENIED_PATTERNS=.env,*.pem,*.key,**/credentials* # Required. The run refuses the call that would exceed it, before making it. SESSION_COST_CEILING_MINOR=500 # Required. Your dated copy of the published prices. Stale beyond a month warns. PRICES_PATH=./prices.json
You are building a production product version of AdaL. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== PRODUCT.md ===== # AdaL · product brief ## Problem The core loop is genuinely reachable: open-source agents already route across model families, run tools, and edit repos, and a weekend of wiring gets you a personal version. What does not fall out of a weekend is the harness around the model, which is where AdaL claims its numbers come from, plus browser-based verification, clustered code review, and the team controls. You end up with an agent that works and a noticeably worse recovery rate on long tasks. ## Product outcome An agent that finishes small tasks in your repository with every command approved, every secret out of reach, every session resumable, every test honoured and every run under a ceiling, and that says in its README where a tuned commercial harness would have done better. ## Target user A builder who needs a maintainable product foundation, not a one-off demo. ## Required capabilities - Node 20 or Python 3.12 - API keys for at least two providers in .env - Git repo to work against - Playwright if you want the browser-verification worker ## Explicit non-goals for v1 - Browser-based verification of a running application. - A graphical interface. - Team accounts and organisation controls. - Any hosted service. - harness tuning: the planning, recovery and verification work that separates a demo agent from one that finishes long tasks - browser-use verification of the app you just changed - review clustering that groups a large diff into risk-ranked units - one bill across every frontier provider instead of six metered API accounts - SSO, SAML/SCIM, zero data retention and org-level model deny lists ## Success criteria - A planted key is confirmed absent from the log and the model's context - A kill mid-call is confirmed reported as incomplete on resume - A step without an acceptance command is confirmed rejected - A test-weakening retry is confirmed to stop with the diff shown - The ceiling is confirmed to refuse before the call ===== BRIEF.md ===== # Build brief · AdaL The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a coding agent for the terminal that plans, delegates to fresh sub-agents, and shows you every command before it runs to replace AdaL. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Runtime: Python 3.12, one file per module, no framework · the harness is the product and every layer between you and it hides behaviour - Providers: Anthropic, OpenAI and Google behind one chat(model, messages, tools) function · a fourth provider is one file, and switching mid-session is a flag - Tools: read_file, write_file, list_dir, run_shell and run_tests, confined to the repository · the agent's reach is exactly this list, and the list is short on purpose - Sessions: Append-only JSONL under .agent/sessions with every call, result and cost · replay and resume need the events, not a summary of them - Verification: The project's own test command after every edit, with a shown diff of any test change · passing by weakening a test is the failure that looks like success ### Data model (create this before Phase 1) - sessions/<id>.jsonl · one event per line: kind, at, step, role, content, tool, args, result, tokens_in, tokens_out, cost_minor, model - plan(step_n, description, acceptance_command, tools_allowed, state, attempts) · written by the planner, run one step per sub-agent - scratchpad.md · the shared record sub-agents append to, and the only context a later sub-agent inherits - approvals(at, command, cwd, decision, session_id) · every shell command shown, and what you said - denied_paths · .env, keys, credentials and anything matching your patterns, refused by read_file before the model sees a byte - prices.json(provider, model, input_per_million, output_per_million, checked_on) · maintained by you from the providers' published prices, dated, never assumed - A tool call and its result are two events, so a crash between them shows on resume as a call with no result rather than as a call that never happened. ### Phase 1 · Tools that cannot reach what they should not Build: Implement chat() over the three providers with keys from .env, a --model flag that switches mid-session, and the five tools. Confine every path to the repository after resolving symlinks. Refuse reads of denied files and redact secret-shaped strings from tool output before it reaches the model. run_shell prints the command and waits for y or n unless --yolo was passed. Trap: The first thing a model does in an unfamiliar repository is read the configuration, and .env is configuration, so within minutes your provider keys are in a prompt on somebody else's server and in your own session log. Deny the files by name and pattern inside read_file, redact key-shaped strings from every tool result, and test both with a planted fake key. Done when: A read of .env or of a file matching a denied pattern is refused with a message the model can act on, tested. A write to a path outside the repository, including through a symlink, is refused. A planted fake key in a file the agent may read is redacted from the tool result and never appears in the session log, asserted by searching the log. A shell command runs only after y, and --yolo is the only way around it. Do not build yet: No sessions, planner, sub-agents, verification loop or cost reporting. ### Phase 2 · Sessions that resume after the worst moment Build: Append every message, tool call, tool result and usage figure to a JSONL file as it happens, flushing per line. Implement --resume to reload the events and the scratchpad and continue from the last complete step, treating a call with no result as not done. Print tokens and cost per provider at the end of every turn, computed from the dated price file. Trap: Writing the session to disk at the end of the run means the run that crashed after forty minutes of work leaves nothing, and the one that crashes is always that one. Append and flush per event, and on resume treat a tool call without a result as never having happened, because you cannot know whether it did. Done when: Killing the process between a tool call and its result leaves a log from which resume reports the incomplete call and re-asks rather than assuming. Replaying a session reproduces the same sequence of events and the same totals. Cost per provider is printed per turn and equals the recorded tokens times the price file, unit tested. A price file older than a stated number of days prints a warning that the figures may be stale. Do not build yet: No planner, sub-agents or verification loop yet. ### Phase 3 · A planner whose steps can be checked Build: A planner call produces numbered steps, each with a description, an acceptance command and the tools it may use. Each step runs as a sub-agent with a fresh context containing the step, the scratchpad and the files it names, and nothing else. The sub-agent appends its result to the scratchpad. A step whose acceptance command fails retries once, then the run stops and reports. Trap: Handing each sub-agent the entire conversation so far defeats the reason for splitting the work, costs a full context per step, and lets step six get confused by step two's abandoned approach. Give it the step, the scratchpad and the named files, and make the planner produce steps you can refuse when an acceptance command is missing or amounts to 'looks good'. Done when: A plan containing a step without an acceptance command is rejected and the planner is re-asked, tested with a fixture plan. Each sub-agent's context contains only the step, the scratchpad and the named files, asserted by inspecting the messages sent. A step failing acceptance twice stops the run with the failing output shown. A sub-agent cannot use a tool outside its step's list, tested by a step that tries. Do not build yet: No automatic test loop or cost ceilings yet. ### Phase 4 · Verification the agent cannot game Build: After any step that edits files, run the project's test command and feed failures back to the same sub-agent for one retry. Detect any change to test files during a retry, show the diff, and require approval before accepting it. Refuse a retry that deletes or skips tests. Keep a summary of what changed per step for the final report. Trap: Given a failing test and permission to edit, a model will sometimes loosen the assertion, mark the test as skipped or delete the file, and the run then reports success with the tests green. Diff the test files after every retry, show the diff, and treat a retry whose only change is to the tests as a failure that needs a human. Done when: A fixture where the implementation is wrong and the test is right ends with a working implementation. A fixture where the only way to go green is to weaken the test ends with a stop and the test diff shown, not a pass. A skipped or deleted test during a retry is refused. The final report lists the files changed per step with the acceptance result. Do not build yet: No cost ceilings, fourth provider or the honest comparison yet. ### Phase 5 · Ceilings, a fourth provider, and where this loses Build: A per-session cost ceiling that stops the run before the next call would exceed it, and a daily ceiling in the price file. Document adding a fourth provider as a single module with the same function shape, and add a fake one in the suite. Write the README section on where this loses to a commercial harness on long tasks: recovery, verification depth and browser checks. Trap: A ceiling checked after the call has already been made is a bill with a warning attached, and on a long planning step with a large context a single call can be most of the budget. Estimate the next call from the context size and refuse before making it, and make the refusal say what it would have cost. Done when: A run stops before the call that would exceed the ceiling, with the estimate shown, tested with a small ceiling. A fake fourth provider is added as one module and works in every code path, asserted in the suite. The README states plainly which parts of a commercial harness this does not have. The session log exports to plain Markdown for reading later. Do not build yet: Nothing after this. ### Out of scope (and why) - Browser automation to verify a running application, which is a second agent with its own failure modes and is part of where the subscription's recovery rate comes from. - A graphical interface, since the terminal is where the approvals, diffs and costs are already readable. - Team accounts, shared sessions and organisation-level model controls, which are the compliance surface companies pay for and a solo developer does not need. - Any hosted service, because the point of this build is that the keys, the code and the session log stay on your machine. ### README must contain - That secret files are denied and key-shaped strings are redacted before the model sees a tool result, tested with a planted key - That every shell command is shown and waits for approval unless --yolo was passed - That sessions are append-only JSONL flushed per event, and resume treats a call without a result as never made - That each sub-agent gets only its step, the scratchpad and the named files, and every step has an acceptance command - That a retry which weakens, skips or deletes a test stops the run rather than passing it - That cost comes from a dated price file you maintain, and a ceiling refuses before the call rather than after ===== ARCHITECTURE.md ===== # Architecture · AdaL ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | Python 3.12, one file per module, no framework | the harness is the product and every layer between you and it hides behaviour | | Providers | Anthropic, OpenAI and Google behind one chat(model, messages, tools) function | a fourth provider is one file, and switching mid-session is a flag | | Tools | read_file, write_file, list_dir, run_shell and run_tests, confined to the repository | the agent's reach is exactly this list, and the list is short on purpose | | Sessions | Append-only JSONL under .agent/sessions with every call, result and cost | replay and resume need the events, not a summary of them | | Verification | The project's own test command after every edit, with a shown diff of any test change | passing by weakening a test is the failure that looks like success | ## Modules Each module has one owner concern and a documented way to replace it. | Module | Owns | How to replace it | | --- | --- | --- | | Providers | One function over every model family. | Any provider, as one module with the same shape. | | Tools | Confined paths, denied secrets, approved shell. | Any implementation, provided the confinement and denial tests still pass. | | Sessions | Append-only events and resume. | Any store, provided a call without a result is treated as not made. | | Orchestration | Plans with acceptance commands and narrow sub-agent contexts. | Any planner, provided steps without acceptance are refused. | | Verification | Tests after edits and test-diff approval. | Not swappable for trusting the model's report of green. | ## Configuration Every runtime setting is an environment variable documented in `.env.example`, validated at startup, with a safe local default wherever one exists. - `ANTHROPIC_API_KEY` · optional, secret · One of at least two providers. Never read by the agent's own tools. - `OPENAI_API_KEY` · optional, secret · One of at least two providers. Never read by the agent's own tools. - `GOOGLE_API_KEY` · optional, secret · One of at least two providers. Never read by the agent's own tools. - `AGENT_DEFAULT_MODEL` · required · Overridden per session by --model. Provider prefix selects the module. - `SESSION_DIR` · required · Append-only JSONL, flushed per event. Add it to .gitignore. - `DENIED_PATTERNS` · required · Refused by read_file before the model sees a byte. Err wide. - `SESSION_COST_CEILING_MINOR` · required · The run refuses the call that would exceed it, before making it. - `PRICES_PATH` · required · Your dated copy of the published prices. Stale beyond a month warns. ## Production baseline - Security: least privilege, input validation at every boundary, secret redaction in logs, rate limits on abuse-prone paths, no invented security primitives. - Data: explicit schema and migrations, transactional writes where integrity matters, backup and restore procedures that have been exercised. - Integrations: adapters around third-party providers, idempotent webhook or job processing, bounded retries, timeouts. - Observability: structured logs with request or operation ids, an error-tracking hook, and health and readiness checks where a server exists. - Quality: unit tests for domain rules, integration tests at module boundaries, one end-to-end test of the critical path. ## Decision records For each dependency in the stack table, keep a short note: why it was chosen, its failure mode, and how it is replaced. Do not add infrastructure until a requirement in `PRODUCT.md` justifies it. ===== AGENTS.md ===== # Agent instructions · AdaL product build - Read `PRODUCT.md` and `ARCHITECTURE.md` before changing code. The stack is fixed: Python 3.12, one file per module, no framework, Anthropic, OpenAI and Google behind one chat(model, messages, tools) function, read_file, write_file, list_dir, run_shell and run_tests, confined to the repository, Append-only JSONL under .agent/sessions with every call, result and cost, The project's own test command after every edit, with a shown diff of any test change. - Implement milestone by milestone from `MILESTONES.md`; keep each change reviewable and leave the application runnable at every commit. - Treat authentication, payments, encryption, imports, webhooks and destructive actions as high-risk boundaries when present. - Never invent cryptography or silently weaken a requirement to make a check pass. - Put every external service behind an interface with a deterministic fake for tests. - Add migrations and rollback or recovery notes for every persistent data change. - Log useful operational context without credentials, tokens, passwords or personal data. - Update documentation and run every check before completing a milestone. ## Known traps - The first thing a model does in an unfamiliar repository is read the configuration, and .env is configuration, so within minutes your provider keys are in a prompt on somebody else's server and in your own session log. Deny the files by name and pattern inside read_file, redact key-shaped strings from every tool result, and test both with a planted fake key. - Writing the session to disk at the end of the run means the run that crashed after forty minutes of work leaves nothing, and the one that crashes is always that one. Append and flush per event, and on resume treat a tool call without a result as never having happened, because you cannot know whether it did. - Handing each sub-agent the entire conversation so far defeats the reason for splitting the work, costs a full context per step, and lets step six get confused by step two's abandoned approach. Give it the step, the scratchpad and the named files, and make the planner produce steps you can refuse when an acceptance command is missing or amounts to 'looks good'. - Given a failing test and permission to edit, a model will sometimes loosen the assertion, mark the test as skipped or delete the file, and the run then reports success with the tests green. Diff the test files after every retry, show the diff, and treat a retry whose only change is to the tests as a failure that needs a human. - A ceiling checked after the call has already been made is a bill with a warning attached, and on a long planning step with a large context a single call can be most of the budget. Estimate the next call from the context size and refuse before making it, and make the refusal say what it would have cost. ===== MILESTONES.md ===== # Delivery milestones · AdaL Estimated effort: **weekend** for the indie phases; the production-only milestones add the trust and operability layer. ## M1 · Tools that cannot reach what they should not The agent reads, writes and runs inside the repository and nowhere else, and never sees a secret. ### Steps 1. Put the providers behind one function Keys from .env, model switch by flag, no provider code anywhere else. Files: `providers.py`, `config.py` 2. Confine paths and deny secrets before the model sees them Resolve symlinks first; test with a planted fake key. Files: `tools.py`, `redact.py`, `tests/test_secrets.py` 3. Show every shell command and wait Print it, wait for y or n, record the answer. Files: `shell.py`, `approvals.py` ### Done when - [ ] Denied files are refused with an actionable message - [ ] Writes outside the repository are refused, symlinks included - [ ] A planted key never reaches the log or the model - [ ] Shell commands wait for approval unless --yolo ### Watch out - The first thing a model does in an unfamiliar repository is read the configuration, and .env is configuration, so within minutes your provider keys are in a prompt on somebody else's server and in your own session log. Deny the files by name and pattern inside read_file, redact key-shaped strings from every tool result, and test both with a planted fake key. ## M2 · Sessions that resume after the worst moment A crash mid-tool-call is visible and recoverable, and every turn's cost is known. ### Steps 1. Append and flush per event The crash that matters is the one after forty minutes. Files: `session.py` 2. Resume from the last complete step A call without a result did not happen, as far as you can know. Files: `resume.py`, `tests/test_resume.py` 3. Price from a dated file, warn when stale Never a number in code; you maintain the file and its date from the published prices. Files: `cost.py`, `prices.json` ### Done when - [ ] A kill mid-call is reported as incomplete on resume - [ ] Replay reproduces the events and totals - [ ] Per-turn cost equals tokens times the price file - [ ] A stale price file warns ### Watch out - Writing the session to disk at the end of the run means the run that crashed after forty minutes of work leaves nothing, and the one that crashes is always that one. Append and flush per event, and on resume treat a tool call without a result as never having happened, because you cannot know whether it did. ## M3 · A planner whose steps can be checked Work is split into steps that each state how you would know they are done, and each runs in a fresh context. ### Steps 1. Require an acceptance command per step A step that cannot fail cannot succeed either. Files: `planner.py`, `tests/test_plan_shape.py` 2. Give each sub-agent a fresh, narrow context The step, the scratchpad, the named files. Assert it. Files: `subagent.py`, `tests/test_context.py` 3. Retry once, then stop and report An agent that retries forever is spending your money on the same mistake. Files: `orchestrator.py` ### Done when - [ ] Steps without acceptance commands are rejected - [ ] Sub-agent context is exactly the step, scratchpad and named files - [ ] Two acceptance failures stop the run with output shown - [ ] Out-of-list tools are refused per step ### Watch out - Handing each sub-agent the entire conversation so far defeats the reason for splitting the work, costs a full context per step, and lets step six get confused by step two's abandoned approach. Give it the step, the scratchpad and the named files, and make the planner produce steps you can refuse when an acceptance command is missing or amounts to 'looks good'. ## M4 · Verification the agent cannot game Edits are tested automatically, and the only way to pass is to make the code work. ### Steps 1. Run the tests after every edit From the project's own configuration, not a guess at the command. Files: `verify.py` 2. Diff test files after a retry and require approval A loosened assertion is the pass that is not a pass. Files: `verify.py`, `tests/test_no_test_weakening.py` 3. Summarise changes per step So the final report is what happened rather than what was planned. Files: `report.py` ### Done when - [ ] A wrong implementation with a right test ends fixed - [ ] A test-weakening retry stops with the diff shown - [ ] Skipped or deleted tests are refused - [ ] The report lists changes per step with results ### Watch out - Given a failing test and permission to edit, a model will sometimes loosen the assertion, mark the test as skipped or delete the file, and the run then reports success with the tests green. Diff the test files after every retry, show the diff, and treat a retry whose only change is to the tests as a failure that needs a human. ## M5 · Ceilings, a fourth provider, and where this loses (production only) A run cannot outspend you, another provider is one file, and the README says where a tuned harness wins. ### Steps 1. Refuse before the call, not after Estimate from context size; a warning after the bill is not a ceiling. Files: `cost.py`, `tests/test_ceiling.py` 2. Add a fake fourth provider in the suite It proves the provider seam is real and documents the shape. Files: `providers.py`, `tests/fake_provider.py`, `README.md` 3. Write the honest paragraph Recovery rate on long tasks is where this loses, and saying so is the point. Files: `README.md` ### Done when - [ ] The run stops before exceeding the ceiling with the estimate shown - [ ] A fake fourth provider works everywhere - [ ] The README names what a commercial harness has that this does not - [ ] Sessions export to Markdown ### Watch out - A ceiling checked after the call has already been made is a bill with a warning attached, and on a long planning step with a large context a single call can be most of the budget. Estimate the next call from the context size and refuse before making it, and make the refusal say what it would have cost. ===== OPERATIONS.md ===== # Operations · AdaL ## Backup Session logs are the record of what the agent did to your repository and the price file is a decision you made; both are small text files and belong in the same backup as the code. The repository itself is under version control, which is the real undo. ## Restore Restore a session log and confirm --resume reproduces its totals and stops at the same incomplete call, since a log that replays differently cannot be trusted to resume correctly either. Do a restore drill before the first real user, and write the date here when it passes. ## Monitoring Cost per session against the ceiling, the retry rate per step, and the count of refused reads and writes. A rising refusal count means the model is probing for something it should not have, which is worth reading the log for. ## Incident checklist A secret in a session log is the incident, and it means the redaction or the denial list failed. Rotate the key first, then find the event in the log, then add the pattern and the test that would have caught it. 1. Contain the issue without destroying evidence or user data. 2. Record the timeline and affected scope. 3. Rotate exposed secrets and revoke compromised sessions or credentials. 4. Restore from a verified backup when needed. 5. Document the root cause, the remediation and the regression test. ## Release gate - [ ] A planted key is confirmed absent from the log and the model's context - [ ] A kill mid-call is confirmed reported as incomplete on resume - [ ] A step without an acceptance command is confirmed rejected - [ ] A test-weakening retry is confirmed to stop with the diff shown - [ ] The ceiling is confirmed to refuse before the call ## Launch constraint Do not market omitted AdaL capabilities as implemented. The non-goals in `PRODUCT.md` remain user-visible limitations until they are deliberately delivered. ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Optional · secret. One of at least two providers. Never read by the agent's own tools. ANTHROPIC_API_KEY=sk-ant-...redacted # Optional · secret. One of at least two providers. Never read by the agent's own tools. OPENAI_API_KEY=sk-...redacted # Optional · secret. One of at least two providers. Never read by the agent's own tools. GOOGLE_API_KEY=AIza...redacted # Required. Overridden per session by --model. Provider prefix selects the module. AGENT_DEFAULT_MODEL=anthropic:claude-sonnet-4-5 # Required. Append-only JSONL, flushed per event. Add it to .gitignore. SESSION_DIR=.agent/sessions # Required. Refused by read_file before the model sees a byte. Err wide. DENIED_PATTERNS=.env,*.pem,*.key,**/credentials* # Required. The run refuses the call that would exceed it, before making it. SESSION_COST_CEILING_MINOR=500 # Required. Your dated copy of the published prices. Stale beyond a month warns. PRICES_PATH=./prices.json
# AdaL · indie build A terminal coding agent whose hard problems are not the model calls but the harness around them: tools that cannot leak a secret or escape the repository, sessions that resume after a crash mid-tool-call, delegation that gives each sub-agent only what it needs, and a verification loop the agent cannot satisfy by weakening the tests. Estimated effort: **weekend**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | Python 3.12, one file per module, no framework | the harness is the product and every layer between you and it hides behaviour | | Providers | Anthropic, OpenAI and Google behind one chat(model, messages, tools) function | a fourth provider is one file, and switching mid-session is a flag | | Tools | read_file, write_file, list_dir, run_shell and run_tests, confined to the repository | the agent's reach is exactly this list, and the list is short on purpose | | Sessions | Append-only JSONL under .agent/sessions with every call, result and cost | replay and resume need the events, not a summary of them | | Verification | The project's own test command after every edit, with a shown diff of any test change | passing by weakening a test is the failure that looks like success | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Python 3.12 or newer** · free - Why: Runs the agent, its tools and the test suite. - Get it: python.org or your package manager. - Verify: python3 --version prints 3.12 or higher - [ ] **API keys for at least two providers** · per token, and a long task can be several pounds - Why: Routing across model families is the point, and a single provider hides every seam the design depends on. - Get it: Per-token billing accounts with two of Anthropic, OpenAI and Google, keys in .env, and note the current published prices for the price file. - Verify: chat() returns from both providers and the recorded cost matches the price file - [ ] **A repository with a real test suite** · free - Why: The verification loop is only meaningful against tests that can actually fail, and a toy project with one passing test exercises none of it. - Get it: A project of your own with at least fifty tests and a configured test command. - Verify: The test command runs from the project's configuration and at least one test can be made to fail - [ ] **Two fixtures for the verification loop** · free - Why: One where the implementation is wrong and the test is right, and one where the only way to go green is to weaken the test, are the two cases the loop must tell apart. - Get it: Write both by hand in the repository's test style. - Verify: The first ends fixed and the second ends stopped with the diff shown - [ ] **A dated price file and your ceilings** · free - Why: Cost is computed from it and a ceiling is derived from it, and a number remembered from a blog post is wrong more often than not. - Get it: Copy each provider's current published prices per million tokens into prices.json with the date checked, and decide a per-session and a daily ceiling. - Verify: prices.json has a checked_on date within the last month and both ceilings are set ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - Browser-based verification of a running application. - A graphical interface. - Team accounts and organisation controls. - Any hosted service. - harness tuning: the planning, recovery and verification work that separates a demo agent from one that finishes long tasks - browser-use verification of the app you just changed - review clustering that groups a large diff into risk-ranked units - one bill across every frontier provider instead of six metered API accounts - SSO, SAML/SCIM, zero data retention and org-level model deny lists If one of those is essential to you, that is the reason to keep paying for AdaL, and the README should say so rather than pretend.
# Build brief · AdaL The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a coding agent for the terminal that plans, delegates to fresh sub-agents, and shows you every command before it runs to replace AdaL. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Runtime: Python 3.12, one file per module, no framework · the harness is the product and every layer between you and it hides behaviour - Providers: Anthropic, OpenAI and Google behind one chat(model, messages, tools) function · a fourth provider is one file, and switching mid-session is a flag - Tools: read_file, write_file, list_dir, run_shell and run_tests, confined to the repository · the agent's reach is exactly this list, and the list is short on purpose - Sessions: Append-only JSONL under .agent/sessions with every call, result and cost · replay and resume need the events, not a summary of them - Verification: The project's own test command after every edit, with a shown diff of any test change · passing by weakening a test is the failure that looks like success ### Data model (create this before Phase 1) - sessions/<id>.jsonl · one event per line: kind, at, step, role, content, tool, args, result, tokens_in, tokens_out, cost_minor, model - plan(step_n, description, acceptance_command, tools_allowed, state, attempts) · written by the planner, run one step per sub-agent - scratchpad.md · the shared record sub-agents append to, and the only context a later sub-agent inherits - approvals(at, command, cwd, decision, session_id) · every shell command shown, and what you said - denied_paths · .env, keys, credentials and anything matching your patterns, refused by read_file before the model sees a byte - prices.json(provider, model, input_per_million, output_per_million, checked_on) · maintained by you from the providers' published prices, dated, never assumed - A tool call and its result are two events, so a crash between them shows on resume as a call with no result rather than as a call that never happened. ### Phase 1 · Tools that cannot reach what they should not Build: Implement chat() over the three providers with keys from .env, a --model flag that switches mid-session, and the five tools. Confine every path to the repository after resolving symlinks. Refuse reads of denied files and redact secret-shaped strings from tool output before it reaches the model. run_shell prints the command and waits for y or n unless --yolo was passed. Trap: The first thing a model does in an unfamiliar repository is read the configuration, and .env is configuration, so within minutes your provider keys are in a prompt on somebody else's server and in your own session log. Deny the files by name and pattern inside read_file, redact key-shaped strings from every tool result, and test both with a planted fake key. Done when: A read of .env or of a file matching a denied pattern is refused with a message the model can act on, tested. A write to a path outside the repository, including through a symlink, is refused. A planted fake key in a file the agent may read is redacted from the tool result and never appears in the session log, asserted by searching the log. A shell command runs only after y, and --yolo is the only way around it. Do not build yet: No sessions, planner, sub-agents, verification loop or cost reporting. ### Phase 2 · Sessions that resume after the worst moment Build: Append every message, tool call, tool result and usage figure to a JSONL file as it happens, flushing per line. Implement --resume to reload the events and the scratchpad and continue from the last complete step, treating a call with no result as not done. Print tokens and cost per provider at the end of every turn, computed from the dated price file. Trap: Writing the session to disk at the end of the run means the run that crashed after forty minutes of work leaves nothing, and the one that crashes is always that one. Append and flush per event, and on resume treat a tool call without a result as never having happened, because you cannot know whether it did. Done when: Killing the process between a tool call and its result leaves a log from which resume reports the incomplete call and re-asks rather than assuming. Replaying a session reproduces the same sequence of events and the same totals. Cost per provider is printed per turn and equals the recorded tokens times the price file, unit tested. A price file older than a stated number of days prints a warning that the figures may be stale. Do not build yet: No planner, sub-agents or verification loop yet. ### Phase 3 · A planner whose steps can be checked Build: A planner call produces numbered steps, each with a description, an acceptance command and the tools it may use. Each step runs as a sub-agent with a fresh context containing the step, the scratchpad and the files it names, and nothing else. The sub-agent appends its result to the scratchpad. A step whose acceptance command fails retries once, then the run stops and reports. Trap: Handing each sub-agent the entire conversation so far defeats the reason for splitting the work, costs a full context per step, and lets step six get confused by step two's abandoned approach. Give it the step, the scratchpad and the named files, and make the planner produce steps you can refuse when an acceptance command is missing or amounts to 'looks good'. Done when: A plan containing a step without an acceptance command is rejected and the planner is re-asked, tested with a fixture plan. Each sub-agent's context contains only the step, the scratchpad and the named files, asserted by inspecting the messages sent. A step failing acceptance twice stops the run with the failing output shown. A sub-agent cannot use a tool outside its step's list, tested by a step that tries. Do not build yet: No automatic test loop or cost ceilings yet. ### Phase 4 · Verification the agent cannot game Build: After any step that edits files, run the project's test command and feed failures back to the same sub-agent for one retry. Detect any change to test files during a retry, show the diff, and require approval before accepting it. Refuse a retry that deletes or skips tests. Keep a summary of what changed per step for the final report. Trap: Given a failing test and permission to edit, a model will sometimes loosen the assertion, mark the test as skipped or delete the file, and the run then reports success with the tests green. Diff the test files after every retry, show the diff, and treat a retry whose only change is to the tests as a failure that needs a human. Done when: A fixture where the implementation is wrong and the test is right ends with a working implementation. A fixture where the only way to go green is to weaken the test ends with a stop and the test diff shown, not a pass. A skipped or deleted test during a retry is refused. The final report lists the files changed per step with the acceptance result. Do not build yet: No cost ceilings, fourth provider or the honest comparison yet. ### Phase 5 · Ceilings, a fourth provider, and where this loses Build: A per-session cost ceiling that stops the run before the next call would exceed it, and a daily ceiling in the price file. Document adding a fourth provider as a single module with the same function shape, and add a fake one in the suite. Write the README section on where this loses to a commercial harness on long tasks: recovery, verification depth and browser checks. Trap: A ceiling checked after the call has already been made is a bill with a warning attached, and on a long planning step with a large context a single call can be most of the budget. Estimate the next call from the context size and refuse before making it, and make the refusal say what it would have cost. Done when: A run stops before the call that would exceed the ceiling, with the estimate shown, tested with a small ceiling. A fake fourth provider is added as one module and works in every code path, asserted in the suite. The README states plainly which parts of a commercial harness this does not have. The session log exports to plain Markdown for reading later. Do not build yet: Nothing after this. ### Out of scope (and why) - Browser automation to verify a running application, which is a second agent with its own failure modes and is part of where the subscription's recovery rate comes from. - A graphical interface, since the terminal is where the approvals, diffs and costs are already readable. - Team accounts, shared sessions and organisation-level model controls, which are the compliance surface companies pay for and a solo developer does not need. - Any hosted service, because the point of this build is that the keys, the code and the session log stay on your machine. ### README must contain - That secret files are denied and key-shaped strings are redacted before the model sees a tool result, tested with a planted key - That every shell command is shown and waits for approval unless --yolo was passed - That sessions are append-only JSONL flushed per event, and resume treats a call without a result as never made - That each sub-agent gets only its step, the scratchpad and the named files, and every step has an acceptance command - That a retry which weakens, skips or deletes a test stops the run rather than passing it - That cost comes from a dated price file you maintain, and a ceiling refuses before the call rather than after
# Agent instructions · AdaL indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: Python 3.12, one file per module, no framework, Anthropic, OpenAI and Google behind one chat(model, messages, tools) function, read_file, write_file, list_dir, run_shell and run_tests, confined to the repository, Append-only JSONL under .agent/sessions with every call, result and cost, The project's own test command after every edit, with a shown diff of any test change. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - The first thing a model does in an unfamiliar repository is read the configuration, and .env is configuration, so within minutes your provider keys are in a prompt on somebody else's server and in your own session log. Deny the files by name and pattern inside read_file, redact key-shaped strings from every tool result, and test both with a planted fake key. - Writing the session to disk at the end of the run means the run that crashed after forty minutes of work leaves nothing, and the one that crashes is always that one. Append and flush per event, and on resume treat a tool call without a result as never having happened, because you cannot know whether it did. - Handing each sub-agent the entire conversation so far defeats the reason for splitting the work, costs a full context per step, and lets step six get confused by step two's abandoned approach. Give it the step, the scratchpad and the named files, and make the planner produce steps you can refuse when an acceptance command is missing or amounts to 'looks good'. - Given a failing test and permission to edit, a model will sometimes loosen the assertion, mark the test as skipped or delete the file, and the run then reports success with the tests green. Diff the test files after every retry, show the diff, and treat a retry whose only change is to the tests as a failure that needs a human.
# Build plan · AdaL A terminal coding agent whose hard problems are not the model calls but the harness around them: tools that cannot leak a secret or escape the repository, sessions that resume after a crash mid-tool-call, delegation that gives each sub-agent only what it needs, and a verification loop the agent cannot satisfy by weakening the tests. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · Tools that cannot reach what they should not The agent reads, writes and runs inside the repository and nowhere else, and never sees a secret. ### Steps 1. Put the providers behind one function Keys from .env, model switch by flag, no provider code anywhere else. Files: `providers.py`, `config.py` 2. Confine paths and deny secrets before the model sees them Resolve symlinks first; test with a planted fake key. Files: `tools.py`, `redact.py`, `tests/test_secrets.py` 3. Show every shell command and wait Print it, wait for y or n, record the answer. Files: `shell.py`, `approvals.py` ### Done when - [ ] Denied files are refused with an actionable message - [ ] Writes outside the repository are refused, symlinks included - [ ] A planted key never reaches the log or the model - [ ] Shell commands wait for approval unless --yolo ### Watch out - The first thing a model does in an unfamiliar repository is read the configuration, and .env is configuration, so within minutes your provider keys are in a prompt on somebody else's server and in your own session log. Deny the files by name and pattern inside read_file, redact key-shaped strings from every tool result, and test both with a planted fake key. ## Phase 2 · Sessions that resume after the worst moment A crash mid-tool-call is visible and recoverable, and every turn's cost is known. ### Steps 1. Append and flush per event The crash that matters is the one after forty minutes. Files: `session.py` 2. Resume from the last complete step A call without a result did not happen, as far as you can know. Files: `resume.py`, `tests/test_resume.py` 3. Price from a dated file, warn when stale Never a number in code; you maintain the file and its date from the published prices. Files: `cost.py`, `prices.json` ### Done when - [ ] A kill mid-call is reported as incomplete on resume - [ ] Replay reproduces the events and totals - [ ] Per-turn cost equals tokens times the price file - [ ] A stale price file warns ### Watch out - Writing the session to disk at the end of the run means the run that crashed after forty minutes of work leaves nothing, and the one that crashes is always that one. Append and flush per event, and on resume treat a tool call without a result as never having happened, because you cannot know whether it did. ## Phase 3 · A planner whose steps can be checked Work is split into steps that each state how you would know they are done, and each runs in a fresh context. ### Steps 1. Require an acceptance command per step A step that cannot fail cannot succeed either. Files: `planner.py`, `tests/test_plan_shape.py` 2. Give each sub-agent a fresh, narrow context The step, the scratchpad, the named files. Assert it. Files: `subagent.py`, `tests/test_context.py` 3. Retry once, then stop and report An agent that retries forever is spending your money on the same mistake. Files: `orchestrator.py` ### Done when - [ ] Steps without acceptance commands are rejected - [ ] Sub-agent context is exactly the step, scratchpad and named files - [ ] Two acceptance failures stop the run with output shown - [ ] Out-of-list tools are refused per step ### Watch out - Handing each sub-agent the entire conversation so far defeats the reason for splitting the work, costs a full context per step, and lets step six get confused by step two's abandoned approach. Give it the step, the scratchpad and the named files, and make the planner produce steps you can refuse when an acceptance command is missing or amounts to 'looks good'. ## Phase 4 · Verification the agent cannot game Edits are tested automatically, and the only way to pass is to make the code work. ### Steps 1. Run the tests after every edit From the project's own configuration, not a guess at the command. Files: `verify.py` 2. Diff test files after a retry and require approval A loosened assertion is the pass that is not a pass. Files: `verify.py`, `tests/test_no_test_weakening.py` 3. Summarise changes per step So the final report is what happened rather than what was planned. Files: `report.py` ### Done when - [ ] A wrong implementation with a right test ends fixed - [ ] A test-weakening retry stops with the diff shown - [ ] Skipped or deleted tests are refused - [ ] The report lists changes per step with results ### Watch out - Given a failing test and permission to edit, a model will sometimes loosen the assertion, mark the test as skipped or delete the file, and the run then reports success with the tests green. Diff the test files after every retry, show the diff, and treat a retry whose only change is to the tests as a failure that needs a human. ## Not in this build - Browser-based verification of a running application. - A graphical interface. - Team accounts and organisation controls. - Any hosted service. ## After v1, if you want it - A read-only exploration mode for an unfamiliar repository at a fraction of the cost - Parallel sub-agents for independent steps, once the scratchpad has locking - A local model as a provider for the cheap steps, which the one-function seam already allows
# Copy to .env and fill in. Never commit .env; this file documents it. # Optional · secret. One of at least two providers. Never read by the agent's own tools. ANTHROPIC_API_KEY=sk-ant-...redacted # Optional · secret. One of at least two providers. Never read by the agent's own tools. OPENAI_API_KEY=sk-...redacted # Optional · secret. One of at least two providers. Never read by the agent's own tools. GOOGLE_API_KEY=AIza...redacted # Required. Overridden per session by --model. Provider prefix selects the module. AGENT_DEFAULT_MODEL=anthropic:claude-sonnet-4-5 # Required. Append-only JSONL, flushed per event. Add it to .gitignore. SESSION_DIR=.agent/sessions # Required. Refused by read_file before the model sees a byte. Err wide. DENIED_PATTERNS=.env,*.pem,*.key,**/credentials* # Required. The run refuses the call that would exceed it, before making it. SESSION_COST_CEILING_MINOR=500 # Required. Your dated copy of the published prices. Stale beyond a month warns. PRICES_PATH=./prices.json
# AdaL · product brief ## Problem The core loop is genuinely reachable: open-source agents already route across model families, run tools, and edit repos, and a weekend of wiring gets you a personal version. What does not fall out of a weekend is the harness around the model, which is where AdaL claims its numbers come from, plus browser-based verification, clustered code review, and the team controls. You end up with an agent that works and a noticeably worse recovery rate on long tasks. ## Product outcome An agent that finishes small tasks in your repository with every command approved, every secret out of reach, every session resumable, every test honoured and every run under a ceiling, and that says in its README where a tuned commercial harness would have done better. ## Target user A builder who needs a maintainable product foundation, not a one-off demo. ## Required capabilities - Node 20 or Python 3.12 - API keys for at least two providers in .env - Git repo to work against - Playwright if you want the browser-verification worker ## Explicit non-goals for v1 - Browser-based verification of a running application. - A graphical interface. - Team accounts and organisation controls. - Any hosted service. - harness tuning: the planning, recovery and verification work that separates a demo agent from one that finishes long tasks - browser-use verification of the app you just changed - review clustering that groups a large diff into risk-ranked units - one bill across every frontier provider instead of six metered API accounts - SSO, SAML/SCIM, zero data retention and org-level model deny lists ## Success criteria - A planted key is confirmed absent from the log and the model's context - A kill mid-call is confirmed reported as incomplete on resume - A step without an acceptance command is confirmed rejected - A test-weakening retry is confirmed to stop with the diff shown - The ceiling is confirmed to refuse before the call
# Build brief · AdaL The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a coding agent for the terminal that plans, delegates to fresh sub-agents, and shows you every command before it runs to replace AdaL. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Runtime: Python 3.12, one file per module, no framework · the harness is the product and every layer between you and it hides behaviour - Providers: Anthropic, OpenAI and Google behind one chat(model, messages, tools) function · a fourth provider is one file, and switching mid-session is a flag - Tools: read_file, write_file, list_dir, run_shell and run_tests, confined to the repository · the agent's reach is exactly this list, and the list is short on purpose - Sessions: Append-only JSONL under .agent/sessions with every call, result and cost · replay and resume need the events, not a summary of them - Verification: The project's own test command after every edit, with a shown diff of any test change · passing by weakening a test is the failure that looks like success ### Data model (create this before Phase 1) - sessions/<id>.jsonl · one event per line: kind, at, step, role, content, tool, args, result, tokens_in, tokens_out, cost_minor, model - plan(step_n, description, acceptance_command, tools_allowed, state, attempts) · written by the planner, run one step per sub-agent - scratchpad.md · the shared record sub-agents append to, and the only context a later sub-agent inherits - approvals(at, command, cwd, decision, session_id) · every shell command shown, and what you said - denied_paths · .env, keys, credentials and anything matching your patterns, refused by read_file before the model sees a byte - prices.json(provider, model, input_per_million, output_per_million, checked_on) · maintained by you from the providers' published prices, dated, never assumed - A tool call and its result are two events, so a crash between them shows on resume as a call with no result rather than as a call that never happened. ### Phase 1 · Tools that cannot reach what they should not Build: Implement chat() over the three providers with keys from .env, a --model flag that switches mid-session, and the five tools. Confine every path to the repository after resolving symlinks. Refuse reads of denied files and redact secret-shaped strings from tool output before it reaches the model. run_shell prints the command and waits for y or n unless --yolo was passed. Trap: The first thing a model does in an unfamiliar repository is read the configuration, and .env is configuration, so within minutes your provider keys are in a prompt on somebody else's server and in your own session log. Deny the files by name and pattern inside read_file, redact key-shaped strings from every tool result, and test both with a planted fake key. Done when: A read of .env or of a file matching a denied pattern is refused with a message the model can act on, tested. A write to a path outside the repository, including through a symlink, is refused. A planted fake key in a file the agent may read is redacted from the tool result and never appears in the session log, asserted by searching the log. A shell command runs only after y, and --yolo is the only way around it. Do not build yet: No sessions, planner, sub-agents, verification loop or cost reporting. ### Phase 2 · Sessions that resume after the worst moment Build: Append every message, tool call, tool result and usage figure to a JSONL file as it happens, flushing per line. Implement --resume to reload the events and the scratchpad and continue from the last complete step, treating a call with no result as not done. Print tokens and cost per provider at the end of every turn, computed from the dated price file. Trap: Writing the session to disk at the end of the run means the run that crashed after forty minutes of work leaves nothing, and the one that crashes is always that one. Append and flush per event, and on resume treat a tool call without a result as never having happened, because you cannot know whether it did. Done when: Killing the process between a tool call and its result leaves a log from which resume reports the incomplete call and re-asks rather than assuming. Replaying a session reproduces the same sequence of events and the same totals. Cost per provider is printed per turn and equals the recorded tokens times the price file, unit tested. A price file older than a stated number of days prints a warning that the figures may be stale. Do not build yet: No planner, sub-agents or verification loop yet. ### Phase 3 · A planner whose steps can be checked Build: A planner call produces numbered steps, each with a description, an acceptance command and the tools it may use. Each step runs as a sub-agent with a fresh context containing the step, the scratchpad and the files it names, and nothing else. The sub-agent appends its result to the scratchpad. A step whose acceptance command fails retries once, then the run stops and reports. Trap: Handing each sub-agent the entire conversation so far defeats the reason for splitting the work, costs a full context per step, and lets step six get confused by step two's abandoned approach. Give it the step, the scratchpad and the named files, and make the planner produce steps you can refuse when an acceptance command is missing or amounts to 'looks good'. Done when: A plan containing a step without an acceptance command is rejected and the planner is re-asked, tested with a fixture plan. Each sub-agent's context contains only the step, the scratchpad and the named files, asserted by inspecting the messages sent. A step failing acceptance twice stops the run with the failing output shown. A sub-agent cannot use a tool outside its step's list, tested by a step that tries. Do not build yet: No automatic test loop or cost ceilings yet. ### Phase 4 · Verification the agent cannot game Build: After any step that edits files, run the project's test command and feed failures back to the same sub-agent for one retry. Detect any change to test files during a retry, show the diff, and require approval before accepting it. Refuse a retry that deletes or skips tests. Keep a summary of what changed per step for the final report. Trap: Given a failing test and permission to edit, a model will sometimes loosen the assertion, mark the test as skipped or delete the file, and the run then reports success with the tests green. Diff the test files after every retry, show the diff, and treat a retry whose only change is to the tests as a failure that needs a human. Done when: A fixture where the implementation is wrong and the test is right ends with a working implementation. A fixture where the only way to go green is to weaken the test ends with a stop and the test diff shown, not a pass. A skipped or deleted test during a retry is refused. The final report lists the files changed per step with the acceptance result. Do not build yet: No cost ceilings, fourth provider or the honest comparison yet. ### Phase 5 · Ceilings, a fourth provider, and where this loses Build: A per-session cost ceiling that stops the run before the next call would exceed it, and a daily ceiling in the price file. Document adding a fourth provider as a single module with the same function shape, and add a fake one in the suite. Write the README section on where this loses to a commercial harness on long tasks: recovery, verification depth and browser checks. Trap: A ceiling checked after the call has already been made is a bill with a warning attached, and on a long planning step with a large context a single call can be most of the budget. Estimate the next call from the context size and refuse before making it, and make the refusal say what it would have cost. Done when: A run stops before the call that would exceed the ceiling, with the estimate shown, tested with a small ceiling. A fake fourth provider is added as one module and works in every code path, asserted in the suite. The README states plainly which parts of a commercial harness this does not have. The session log exports to plain Markdown for reading later. Do not build yet: Nothing after this. ### Out of scope (and why) - Browser automation to verify a running application, which is a second agent with its own failure modes and is part of where the subscription's recovery rate comes from. - A graphical interface, since the terminal is where the approvals, diffs and costs are already readable. - Team accounts, shared sessions and organisation-level model controls, which are the compliance surface companies pay for and a solo developer does not need. - Any hosted service, because the point of this build is that the keys, the code and the session log stay on your machine. ### README must contain - That secret files are denied and key-shaped strings are redacted before the model sees a tool result, tested with a planted key - That every shell command is shown and waits for approval unless --yolo was passed - That sessions are append-only JSONL flushed per event, and resume treats a call without a result as never made - That each sub-agent gets only its step, the scratchpad and the named files, and every step has an acceptance command - That a retry which weakens, skips or deletes a test stops the run rather than passing it - That cost comes from a dated price file you maintain, and a ceiling refuses before the call rather than after
# Architecture · AdaL ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | Python 3.12, one file per module, no framework | the harness is the product and every layer between you and it hides behaviour | | Providers | Anthropic, OpenAI and Google behind one chat(model, messages, tools) function | a fourth provider is one file, and switching mid-session is a flag | | Tools | read_file, write_file, list_dir, run_shell and run_tests, confined to the repository | the agent's reach is exactly this list, and the list is short on purpose | | Sessions | Append-only JSONL under .agent/sessions with every call, result and cost | replay and resume need the events, not a summary of them | | Verification | The project's own test command after every edit, with a shown diff of any test change | passing by weakening a test is the failure that looks like success | ## Modules Each module has one owner concern and a documented way to replace it. | Module | Owns | How to replace it | | --- | --- | --- | | Providers | One function over every model family. | Any provider, as one module with the same shape. | | Tools | Confined paths, denied secrets, approved shell. | Any implementation, provided the confinement and denial tests still pass. | | Sessions | Append-only events and resume. | Any store, provided a call without a result is treated as not made. | | Orchestration | Plans with acceptance commands and narrow sub-agent contexts. | Any planner, provided steps without acceptance are refused. | | Verification | Tests after edits and test-diff approval. | Not swappable for trusting the model's report of green. | ## Configuration Every runtime setting is an environment variable documented in `.env.example`, validated at startup, with a safe local default wherever one exists. - `ANTHROPIC_API_KEY` · optional, secret · One of at least two providers. Never read by the agent's own tools. - `OPENAI_API_KEY` · optional, secret · One of at least two providers. Never read by the agent's own tools. - `GOOGLE_API_KEY` · optional, secret · One of at least two providers. Never read by the agent's own tools. - `AGENT_DEFAULT_MODEL` · required · Overridden per session by --model. Provider prefix selects the module. - `SESSION_DIR` · required · Append-only JSONL, flushed per event. Add it to .gitignore. - `DENIED_PATTERNS` · required · Refused by read_file before the model sees a byte. Err wide. - `SESSION_COST_CEILING_MINOR` · required · The run refuses the call that would exceed it, before making it. - `PRICES_PATH` · required · Your dated copy of the published prices. Stale beyond a month warns. ## Production baseline - Security: least privilege, input validation at every boundary, secret redaction in logs, rate limits on abuse-prone paths, no invented security primitives. - Data: explicit schema and migrations, transactional writes where integrity matters, backup and restore procedures that have been exercised. - Integrations: adapters around third-party providers, idempotent webhook or job processing, bounded retries, timeouts. - Observability: structured logs with request or operation ids, an error-tracking hook, and health and readiness checks where a server exists. - Quality: unit tests for domain rules, integration tests at module boundaries, one end-to-end test of the critical path. ## Decision records For each dependency in the stack table, keep a short note: why it was chosen, its failure mode, and how it is replaced. Do not add infrastructure until a requirement in `PRODUCT.md` justifies it.
# Agent instructions · AdaL product build - Read `PRODUCT.md` and `ARCHITECTURE.md` before changing code. The stack is fixed: Python 3.12, one file per module, no framework, Anthropic, OpenAI and Google behind one chat(model, messages, tools) function, read_file, write_file, list_dir, run_shell and run_tests, confined to the repository, Append-only JSONL under .agent/sessions with every call, result and cost, The project's own test command after every edit, with a shown diff of any test change. - Implement milestone by milestone from `MILESTONES.md`; keep each change reviewable and leave the application runnable at every commit. - Treat authentication, payments, encryption, imports, webhooks and destructive actions as high-risk boundaries when present. - Never invent cryptography or silently weaken a requirement to make a check pass. - Put every external service behind an interface with a deterministic fake for tests. - Add migrations and rollback or recovery notes for every persistent data change. - Log useful operational context without credentials, tokens, passwords or personal data. - Update documentation and run every check before completing a milestone. ## Known traps - The first thing a model does in an unfamiliar repository is read the configuration, and .env is configuration, so within minutes your provider keys are in a prompt on somebody else's server and in your own session log. Deny the files by name and pattern inside read_file, redact key-shaped strings from every tool result, and test both with a planted fake key. - Writing the session to disk at the end of the run means the run that crashed after forty minutes of work leaves nothing, and the one that crashes is always that one. Append and flush per event, and on resume treat a tool call without a result as never having happened, because you cannot know whether it did. - Handing each sub-agent the entire conversation so far defeats the reason for splitting the work, costs a full context per step, and lets step six get confused by step two's abandoned approach. Give it the step, the scratchpad and the named files, and make the planner produce steps you can refuse when an acceptance command is missing or amounts to 'looks good'. - Given a failing test and permission to edit, a model will sometimes loosen the assertion, mark the test as skipped or delete the file, and the run then reports success with the tests green. Diff the test files after every retry, show the diff, and treat a retry whose only change is to the tests as a failure that needs a human. - A ceiling checked after the call has already been made is a bill with a warning attached, and on a long planning step with a large context a single call can be most of the budget. Estimate the next call from the context size and refuse before making it, and make the refusal say what it would have cost.
# Delivery milestones · AdaL Estimated effort: **weekend** for the indie phases; the production-only milestones add the trust and operability layer. ## M1 · Tools that cannot reach what they should not The agent reads, writes and runs inside the repository and nowhere else, and never sees a secret. ### Steps 1. Put the providers behind one function Keys from .env, model switch by flag, no provider code anywhere else. Files: `providers.py`, `config.py` 2. Confine paths and deny secrets before the model sees them Resolve symlinks first; test with a planted fake key. Files: `tools.py`, `redact.py`, `tests/test_secrets.py` 3. Show every shell command and wait Print it, wait for y or n, record the answer. Files: `shell.py`, `approvals.py` ### Done when - [ ] Denied files are refused with an actionable message - [ ] Writes outside the repository are refused, symlinks included - [ ] A planted key never reaches the log or the model - [ ] Shell commands wait for approval unless --yolo ### Watch out - The first thing a model does in an unfamiliar repository is read the configuration, and .env is configuration, so within minutes your provider keys are in a prompt on somebody else's server and in your own session log. Deny the files by name and pattern inside read_file, redact key-shaped strings from every tool result, and test both with a planted fake key. ## M2 · Sessions that resume after the worst moment A crash mid-tool-call is visible and recoverable, and every turn's cost is known. ### Steps 1. Append and flush per event The crash that matters is the one after forty minutes. Files: `session.py` 2. Resume from the last complete step A call without a result did not happen, as far as you can know. Files: `resume.py`, `tests/test_resume.py` 3. Price from a dated file, warn when stale Never a number in code; you maintain the file and its date from the published prices. Files: `cost.py`, `prices.json` ### Done when - [ ] A kill mid-call is reported as incomplete on resume - [ ] Replay reproduces the events and totals - [ ] Per-turn cost equals tokens times the price file - [ ] A stale price file warns ### Watch out - Writing the session to disk at the end of the run means the run that crashed after forty minutes of work leaves nothing, and the one that crashes is always that one. Append and flush per event, and on resume treat a tool call without a result as never having happened, because you cannot know whether it did. ## M3 · A planner whose steps can be checked Work is split into steps that each state how you would know they are done, and each runs in a fresh context. ### Steps 1. Require an acceptance command per step A step that cannot fail cannot succeed either. Files: `planner.py`, `tests/test_plan_shape.py` 2. Give each sub-agent a fresh, narrow context The step, the scratchpad, the named files. Assert it. Files: `subagent.py`, `tests/test_context.py` 3. Retry once, then stop and report An agent that retries forever is spending your money on the same mistake. Files: `orchestrator.py` ### Done when - [ ] Steps without acceptance commands are rejected - [ ] Sub-agent context is exactly the step, scratchpad and named files - [ ] Two acceptance failures stop the run with output shown - [ ] Out-of-list tools are refused per step ### Watch out - Handing each sub-agent the entire conversation so far defeats the reason for splitting the work, costs a full context per step, and lets step six get confused by step two's abandoned approach. Give it the step, the scratchpad and the named files, and make the planner produce steps you can refuse when an acceptance command is missing or amounts to 'looks good'. ## M4 · Verification the agent cannot game Edits are tested automatically, and the only way to pass is to make the code work. ### Steps 1. Run the tests after every edit From the project's own configuration, not a guess at the command. Files: `verify.py` 2. Diff test files after a retry and require approval A loosened assertion is the pass that is not a pass. Files: `verify.py`, `tests/test_no_test_weakening.py` 3. Summarise changes per step So the final report is what happened rather than what was planned. Files: `report.py` ### Done when - [ ] A wrong implementation with a right test ends fixed - [ ] A test-weakening retry stops with the diff shown - [ ] Skipped or deleted tests are refused - [ ] The report lists changes per step with results ### Watch out - Given a failing test and permission to edit, a model will sometimes loosen the assertion, mark the test as skipped or delete the file, and the run then reports success with the tests green. Diff the test files after every retry, show the diff, and treat a retry whose only change is to the tests as a failure that needs a human. ## M5 · Ceilings, a fourth provider, and where this loses (production only) A run cannot outspend you, another provider is one file, and the README says where a tuned harness wins. ### Steps 1. Refuse before the call, not after Estimate from context size; a warning after the bill is not a ceiling. Files: `cost.py`, `tests/test_ceiling.py` 2. Add a fake fourth provider in the suite It proves the provider seam is real and documents the shape. Files: `providers.py`, `tests/fake_provider.py`, `README.md` 3. Write the honest paragraph Recovery rate on long tasks is where this loses, and saying so is the point. Files: `README.md` ### Done when - [ ] The run stops before exceeding the ceiling with the estimate shown - [ ] A fake fourth provider works everywhere - [ ] The README names what a commercial harness has that this does not - [ ] Sessions export to Markdown ### Watch out - A ceiling checked after the call has already been made is a bill with a warning attached, and on a long planning step with a large context a single call can be most of the budget. Estimate the next call from the context size and refuse before making it, and make the refusal say what it would have cost.
# Operations · AdaL ## Backup Session logs are the record of what the agent did to your repository and the price file is a decision you made; both are small text files and belong in the same backup as the code. The repository itself is under version control, which is the real undo. ## Restore Restore a session log and confirm --resume reproduces its totals and stops at the same incomplete call, since a log that replays differently cannot be trusted to resume correctly either. Do a restore drill before the first real user, and write the date here when it passes. ## Monitoring Cost per session against the ceiling, the retry rate per step, and the count of refused reads and writes. A rising refusal count means the model is probing for something it should not have, which is worth reading the log for. ## Incident checklist A secret in a session log is the incident, and it means the redaction or the denial list failed. Rotate the key first, then find the event in the log, then add the pattern and the test that would have caught it. 1. Contain the issue without destroying evidence or user data. 2. Record the timeline and affected scope. 3. Rotate exposed secrets and revoke compromised sessions or credentials. 4. Restore from a verified backup when needed. 5. Document the root cause, the remediation and the regression test. ## Release gate - [ ] A planted key is confirmed absent from the log and the model's context - [ ] A kill mid-call is confirmed reported as incomplete on resume - [ ] A step without an acceptance command is confirmed rejected - [ ] A test-weakening retry is confirmed to stop with the diff shown - [ ] The ceiling is confirmed to refuse before the call ## Launch constraint Do not market omitted AdaL capabilities as implemented. The non-goals in `PRODUCT.md` remain user-visible limitations until they are deliberately delivered.
# Copy to .env and fill in. Never commit .env; this file documents it. # Optional · secret. One of at least two providers. Never read by the agent's own tools. ANTHROPIC_API_KEY=sk-ant-...redacted # Optional · secret. One of at least two providers. Never read by the agent's own tools. OPENAI_API_KEY=sk-...redacted # Optional · secret. One of at least two providers. Never read by the agent's own tools. GOOGLE_API_KEY=AIza...redacted # Required. Overridden per session by --model. Provider prefix selects the module. AGENT_DEFAULT_MODEL=anthropic:claude-sonnet-4-5 # Required. Append-only JSONL, flushed per event. Add it to .gitignore. SESSION_DIR=.agent/sessions # Required. Refused by read_file before the model sees a byte. Err wide. DENIED_PATTERNS=.env,*.pem,*.key,**/credentials* # Required. The run refuses the call that would exceed it, before making it. SESSION_COST_CEILING_MINOR=500 # Required. Your dated copy of the published prices. Stale beyond a month warns. PRICES_PATH=./prices.json
$ choose a build depth, inspect the files, then open the complete pack in your agent
Because the gap between an agent that runs and an agent that finishes is mostly unglamorous harness work, and nobody wants to maintain it on a weekend. The flat subscription across every frontier model is the other half: DIY means holding API accounts with six vendors and watching the meter on every long run.
xharness tuning: the planning, recovery and verification work that separates a demo agent from one that finishes long tasks
xbrowser-use verification of the app you just changed
xreview clustering that groups a large diff into risk-ranked units
xone bill across every frontier provider instead of six metered API accounts
xSSO, SAML/SCIM, zero data retention and org-level model deny lists
Don't feel like building it? These folks already made it free.
all 3 free alternatives to AdaL →· no votes, no pay-to-list · just what's real
AdaL pricing
| plan | monthly | annual (per mo) | what you get |
|---|---|---|---|
| free 7-day access | $0 | — | Full access for the first week only; the published page states no numeric usage cap for the trial. |
| pro | $20 | $16.60 | Standard usage, positioned for short coding sprints in small codebases; no published numeric token or request allowance. |
| max | $100 | $83 | Described as 5x usage relative to Pro; the base unit behind the multiplier is not published. |
| max+ | $200 | $166 | Described as 20x usage relative to Pro, with the widest model access. |
| teams & enterprise | custom | — | Up to 150 seats, custom usage limits, SSO, SAML/SCIM, zero data retention, org-level model and autonomy controls. Price is quote-only. |
free tierno free tier, only a 7-day trial
billingmonthly + annual for self-serve plans, annual advertised at 17% off; Teams and Enterprise are custom-quoted
hidden costsModel inference is included in the subscription rather than billed per token, so the usage multipliers between Pro, Max and Max+ are the real cost lever and are not expressed in published numeric limits.
verified 2026-08-14 · source ↗
Is AdaL free?
There is no permanently free plan; new accounts get 7 days of free access and then have to pick a paid tier. Paid is Pro at $20/mo (checked 2026-08-14).
Vibecode AdaL
Kinda. The core of AdaL is buildable in a weekend with the prompt on this page, but there are real gaps: harness tuning: the planning, recovery and verification work that separates a demo agent from one that finishes long tasks, browser-use verification of the app you just changed. Read the honest list above before committing.
How much does AdaL cost?
AdaL costs about $20/month (Pro, checked 2026-08-14), which is $240 per year.
What do I lose by replacing AdaL?
Honestly: harness tuning: the planning, recovery and verification work that separates a demo agent from one that finishes long tasks; browser-use verification of the app you just changed; review clustering that groups a large diff into risk-ranked units; one bill across every frontier provider instead of six metered API accounts; SSO, SAML/SCIM, zero data retention and org-level model deny lists. If any of those are load-bearing for you, keep paying.
Is there an open-source alternative to AdaL?
Yes: OpenCode (A terminal coding agent with no loyalty to any model vendor; you still pay the meter.) Cline (An agent that lives in the editor you already use; the model bill is still yours.) Goose (A desktop and terminal agent with real extension support, and no pretence that the model is free.) All 3 curated free alternatives are at vibecodeit.com/adal/alternatives. The prompt is for when you want it exactly your way.