atom-agent 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +97 -0
- package/README.md +13 -4
- package/atom.example.json +11 -0
- package/dist/App.js +923 -200
- package/dist/adapters.js +82 -13
- package/dist/agent/goal-evaluator.js +69 -0
- package/dist/agent/loop.js +517 -76
- package/dist/cli.js +11 -3
- package/dist/compact.js +41 -15
- package/dist/config.js +43 -7
- package/dist/context-manager.js +16 -198
- package/dist/context-windows.js +4 -2
- package/dist/env-block.js +5 -5
- package/dist/extension-commands.js +196 -0
- package/dist/extension-ui.js +153 -0
- package/dist/extensions.js +1571 -0
- package/dist/goal.js +583 -0
- package/dist/project-trust.js +96 -0
- package/dist/providers.js +6 -6
- package/dist/scheduler.js +74 -36
- package/dist/session.js +23 -5
- package/dist/sessions.js +25 -6
- package/dist/telemetry-dashboard.js +28 -0
- package/dist/telemetry.js +39 -0
- package/dist/tools/compaction-hooks.js +165 -0
- package/dist/tools/custom.js +189 -0
- package/dist/tools/intercept.js +145 -0
- package/dist/tools/overrides.js +105 -0
- package/dist/tools/provider-hooks.js +224 -0
- package/dist/tools/registry.js +246 -17
- package/dist/tools.js +44 -0
- package/dist/ui/diff-panel.js +5 -5
- package/dist/ui/diff-view.js +3 -2
- package/dist/ui/diff.js +7 -52
- package/dist/ui/modals.js +5 -5
- package/dist/ui/palette.js +1 -1
- package/dist/ui/side-by-side.js +7 -5
- package/dist/ui/status-bar.js +80 -5
- package/dist/ui/transcript.js +3 -3
- package/dist/zen.js +305 -75
- package/documentation/architecture.md +114 -0
- package/documentation/cli.md +82 -0
- package/documentation/compaction.md +50 -0
- package/documentation/configuration.md +111 -0
- package/documentation/development.md +62 -0
- package/documentation/extensions.md +160 -0
- package/documentation/getting-started.md +63 -0
- package/documentation/goals.md +41 -0
- package/documentation/index.md +41 -0
- package/documentation/observability.md +70 -0
- package/documentation/permissions.md +66 -0
- package/documentation/providers.md +78 -0
- package/documentation/sessions.md +92 -0
- package/documentation/skills.md +57 -0
- package/documentation/tools.md +94 -0
- package/documentation/troubleshooting.md +54 -0
- package/examples/extensions/01-audit-gate.js +24 -0
- package/examples/extensions/02-notes-tool.js +32 -0
- package/examples/extensions/03-custom-command.js +32 -0
- package/package.json +6 -2
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
ATOM is a flat-modules codebase with a few directories where a real seam
|
|
4
|
+
exists. The rule is responsibility + dependency direction, never line counts:
|
|
5
|
+
coherent single-file modules stay single files.
|
|
6
|
+
|
|
7
|
+
## Module map
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
cli.tsx -> App.tsx (App) -> everything (UI root, the only React owner)
|
|
11
|
+
|
|
|
12
|
+
ui/{transcript,input,todo-panel} (prop-driven memo leaves, no App import)
|
|
13
|
+
ui/{pickers,modals,status-bar,live-tail,palette} (presentational shells; status-bar
|
|
14
|
+
formats via context-windows, approval text arrives pre-formatted)
|
|
15
|
+
ui/theme (design tokens: every color/glyph/separator/border/spacing value;
|
|
16
|
+
components reference tokens, never literals)
|
|
17
|
+
ui/markdown (zero-dep markdown for assistant turns: headings/lists/code/
|
|
18
|
+
links/quotes; bounded parse cache; MarkdownStream auto-closes transient
|
|
19
|
+
markers mid-stream and converges to the committed shape; tool lines stay
|
|
20
|
+
full-fidelity — ToolLine renders call/warning/denied/retry/cancel states
|
|
21
|
+
from shape, suffixing `· Ns` on slow calls from display-only Turn.ms)
|
|
22
|
+
ui/errors (typed error cards for tool turns: tool/denial/network/model/
|
|
23
|
+
cancelled/config/internal; adjacent [audit label, error detail] pairs
|
|
24
|
+
merge in TranscriptView; full diagnostics stay in the inspector store)
|
|
25
|
+
ui/transcript (static scrollback: committed turns print once via <Static>
|
|
26
|
+
and are never rewritten — a full-page transcript no longer flashes on
|
|
27
|
+
every keystroke (Ink clearTerminal path); commit frontier follows by
|
|
28
|
+
default, PgUp//autoscroll-off freezes new commits with a `↓ N new`
|
|
29
|
+
indicator, End resumes the backlog; banner once per Static identity;
|
|
30
|
+
/thinking toggle is forward-only for committed blocks; global turn keys
|
|
31
|
+
keep rows stable)
|
|
32
|
+
ui/tool-inspector (Ctrl+O browse + expand panel for retained tool results:
|
|
33
|
+
capped store, windowed list, viewport-scrolled output with explicit
|
|
34
|
+
truncation; transcript untouched — expansion lives in the
|
|
35
|
+
dynamic zone)
|
|
36
|
+
ui/activity (working-state model: thinking-gap + verb-mapped tool lines;
|
|
37
|
+
liveness from ticking elapsed seconds, never animated spinners)
|
|
38
|
+
ui/modals (approval/question dialogs: arrows+Enter select, y/a/t/n pinned;
|
|
39
|
+
command preview split from the audit prefix; policy untouched)
|
|
40
|
+
ui/diff, ui/highlight, ui/diff-view, ui/side-by-side (zero-dep diff stack:
|
|
41
|
+
unified engine + line-scoped syntax tokenizer + unified view +
|
|
42
|
+
side-by-side BEFORE/AFTER view with narrow-terminal fallback; approved
|
|
43
|
+
write/edit results commit their diff on the audit turn, stripped on save)
|
|
44
|
+
ui/diff-panel (session-changes review: file list grouped by path with
|
|
45
|
+
per-file side-by-side detail; same renderer as the transcript)
|
|
46
|
+
ui/input + input-model (multiline box with line/col cursor, Ctrl+J newline,
|
|
47
|
+
bracketed paste via usePaste, readline kills, in-memory prompt history;
|
|
48
|
+
Enter always sends; slash menu stays single-line)
|
|
49
|
+
slash matching (App-owned: exact input collapses to one command;
|
|
50
|
+
otherwise prefix tier stable + fuzzy tier scored, one
|
|
51
|
+
matcher for commands and skills; skill rows carry truncated
|
|
52
|
+
descriptions; usage footer reuses the commands' own usage strings)
|
|
53
|
+
|
|
|
54
|
+
agent/loop -> agent/gates -> tools/* (getTodos)
|
|
55
|
+
| \---> agent/types (types only)
|
|
56
|
+
| \---> scheduler -> tools (validators)
|
|
57
|
+
| \---> config, context-manager, tools (executors)
|
|
58
|
+
v
|
|
59
|
+
zen.ts (transports, dispatch, prefs, prompt assembly)
|
|
60
|
+
├── re-exports agent/* + context-manager surface (compat)
|
|
61
|
+
└── imports agent/loop (one direction only)
|
|
62
|
+
|
|
|
63
|
+
tools.ts (pure barrel)
|
|
64
|
+
├── tools/registry (names, validation, dispatch, schemas)
|
|
65
|
+
├── tools/filesystem (read/write/edit + snapshots + fingerprints)
|
|
66
|
+
├── tools/search (grep/glob) tools/shell (bash/tasks)
|
|
67
|
+
├── tools/web (fetch/search) tools/todo (checklist state)
|
|
68
|
+
└── tools/shared, tools/overflow, tools/fingerprints (kernel)
|
|
69
|
+
|
|
|
70
|
+
context-manager.ts, compact.ts, prompt-cache.ts, env-block.ts, context-windows.ts (context systems: flat files, one seam each)
|
|
71
|
+
session.ts + snapshots.ts (persistence + pre-mutation snapshots)
|
|
72
|
+
policy.ts + permissions.ts + rollback.ts (policy decisions, rule matching, turn rollback)
|
|
73
|
+
skills.ts — registry, loader, matcher (intentionally one file:
|
|
74
|
+
discovery and parsing must stay byte-identical)
|
|
75
|
+
providers.ts, adapters.ts, kilo.ts (provider types, wire adapters, Kilo gateway)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Dependency rules (enforced by tests/architecture.test.ts)
|
|
79
|
+
|
|
80
|
+
- The runtime import graph is acyclic (type-only imports don't count —
|
|
81
|
+
they erase at compile).
|
|
82
|
+
- `react`/`ink` live only in `cli.tsx`, `App.tsx`, `ui/*`. No runtime
|
|
83
|
+
module imports the UI; tools, providers, context-manager, policy,
|
|
84
|
+
scheduler, and everything under `agent/` are UI-free.
|
|
85
|
+
- `policy.ts` depends only on `permissions.ts` at runtime (plus types):
|
|
86
|
+
it stays usable by future subagents with no fs/net/UI baggage.
|
|
87
|
+
- Inside `tools/`, executors never import the registry — the registry
|
|
88
|
+
owns names/validation/dispatch and sits above them.
|
|
89
|
+
- Inside `agent/`, loop/gates/types never import `zen` at runtime —
|
|
90
|
+
`zen.ts` re-exports them for compatibility, never the reverse.
|
|
91
|
+
- The scheduler reasons from `TOOL_EFFECTS` metadata, not per-tool
|
|
92
|
+
branches; missing metadata fails safe to serial.
|
|
93
|
+
|
|
94
|
+
## What was deliberately NOT split
|
|
95
|
+
|
|
96
|
+
- `skills.ts`: registry + loader + matcher share one parser that must
|
|
97
|
+
stay byte-identical across paths (says so in its header).
|
|
98
|
+
- `App.tsx` beyond the `ui/` leaves: the rest is hooks-entangled
|
|
99
|
+
session state — splitting it further would be prop-drilling, not
|
|
100
|
+
boundaries. Pure helpers already live at module scope and are
|
|
101
|
+
directly unit-tested (slash menu, pickers, filters).
|
|
102
|
+
- `zen.ts` transports: one dispatch + per-kind wire functions belong
|
|
103
|
+
together; the loop, gates, and types now live in `agent/`.
|
|
104
|
+
- Flat coherent modules (`config`, `session`, `snapshots`, `compact`,
|
|
105
|
+
`prompt-cache`, `env-block`, `auth`, `system`): renaming them into
|
|
106
|
+
directories would be motion without meaning.
|
|
107
|
+
|
|
108
|
+
## Verification
|
|
109
|
+
|
|
110
|
+
`tests/architecture.test.ts` scans the real source on every run, so
|
|
111
|
+
drift fails loudly with the exact file + edge. Behavior is pinned by
|
|
112
|
+
the full suite: every extraction above kept all
|
|
113
|
+
importer paths working (barrels + re-exports), and the suite is the
|
|
114
|
+
proof — no behavior change was made or needed.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# CLI and TUI
|
|
2
|
+
|
|
3
|
+
ATOM is an Ink (React) TUI. Entry is `src/cli.tsx`, rendered by `src/App.tsx`. There is no persistent header, only the launch-time banner. The status line is the sole info bar.
|
|
4
|
+
|
|
5
|
+
## Launch
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm start # run the TUI from source (needs a TTY)
|
|
9
|
+
atom # run the installed binary (runs dist/cli.js)
|
|
10
|
+
atom --help # usage, env vars, commands, providers (exits, no TUI)
|
|
11
|
+
atom --dashboard # write ~/.atom/telemetry/dashboard.html and exit (no TUI)
|
|
12
|
+
atom --serve [--port <n>] # serve the live observability webUI on loopback (no TUI, Ctrl+C stops)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`--help` (or `-h`) prints usage and exits. `--dashboard` and `--serve` handle local observability without starting the TUI (see [Observability](observability.md)). Any other invocation starts the TUI, even without a key.
|
|
16
|
+
|
|
17
|
+
## Slash commands
|
|
18
|
+
|
|
19
|
+
Type `/` to autocomplete as you type. Full registry (`src/App.tsx`):
|
|
20
|
+
|
|
21
|
+
| Command | What it does |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `/model` | Unified model picker: active provider first, then other keyed providers plus the always-visible keyless Kilo list (free models badged `(free)`, `free` filters them). Cross-provider pick switches provider |
|
|
24
|
+
| `/models [refresh]` | Local discovery status; `refresh` re-probes local servers (or the Kilo gateway catalog while Kilo is active) |
|
|
25
|
+
| `/provider` | Provider plus key picker; validates and stores in `~/.atom/auth.json` (Kilo key optional — empty Enter continues anonymously) |
|
|
26
|
+
| `/new` | Start a brand-new session (conversation plus counters reset, previous kept for `/resume`) |
|
|
27
|
+
| `/rename <name>` | Rename the current session (id and history untouched; quotes optional) |
|
|
28
|
+
| `/plan`, `/yolo` | Retired as typed commands — `Tab` is the only mode switcher (normal → yolo → plan → normal); typing them explains this instead of switching |
|
|
29
|
+
| `/effort` | Reasoning-effort picker (`Auto`/`Low`/`Medium`/`High`/`Max`; sent for every model on every provider — `reasoning_effort` on OpenAI-chat, thinking budget on Anthropic, thinking level on Gemini; `Auto` omits it) |
|
|
30
|
+
| `/tools` | List tools with one-line descriptions |
|
|
31
|
+
| `/skills` | List installed skills (project plus global) |
|
|
32
|
+
| `/skill` | Invoke a skill by name (`/skill:name`; skills also complete in the `/` menu) |
|
|
33
|
+
| `/context` | Show context usage by source (system, tools, history, skills, config, prefix-cache) |
|
|
34
|
+
| `/queue` | List queued follow-ups (`/queue clear` wipes; cap 10, in-memory only) |
|
|
35
|
+
| `/steer` | Steer the running turn, or send when idle (`/steer <text>`) |
|
|
36
|
+
| `/autoscroll` | Toggle following new output (on by default; bare toggles, `on|off` sets it; off freezes the view mid-turn) |
|
|
37
|
+
| `/mode` | Print the current permission mode |
|
|
38
|
+
| `/trust` | Toggle session trust: auto-approve write/edit/bash without full yolo. Again revokes |
|
|
39
|
+
| `/allow <tool[:glob]>` | Pre-approve a tool pattern this session |
|
|
40
|
+
| `/deny <tool[:glob]>` | Forbid a tool pattern this session. Deny wins over trust/yolo |
|
|
41
|
+
| `/rules` | List session allow/deny rules. `/rules clear` wipes them |
|
|
42
|
+
| `/clear` | Clear conversation history (keeps session token totals) |
|
|
43
|
+
| `/compact [focus]` | Summarize older turns into one summary. Optional focus text |
|
|
44
|
+
| `/goal <objective>` | Pin one session goal (bare shows it; `pause` / `resume` / `clear` manage it; see [Goals](goals.md)) |
|
|
45
|
+
| `/resume` | Restore the last saved session (turns, history, settings, usage) |
|
|
46
|
+
| `/session [filter]` | Switch the active session (interactive most-recent-first picker with fuzzy filter; `Enter` switches, `Esc` cancels) |
|
|
47
|
+
| `/telemetry` | Show the local observability summary (sessions, tokens, tools) |
|
|
48
|
+
| `/dashboard` | Write the local observability dashboard page and show its path |
|
|
49
|
+
| `/rewind` | Restore files to a session checkpoint. Files only, never shell side effects |
|
|
50
|
+
| `/help` | List commands with one-liners |
|
|
51
|
+
| `/exit`, `/quit` | Exit ATOM |
|
|
52
|
+
|
|
53
|
+
`/compact`, `/allow`, `/deny`, `/rules` accept prefix forms (`/compact focus...`, `/allow bash:npm test*`). `/rename` takes the rest of the line as the name; `/session` takes an optional initial filter.
|
|
54
|
+
|
|
55
|
+
## Keyboard
|
|
56
|
+
|
|
57
|
+
- `Tab`: cycle permission mode normal → yolo → plan → normal (in the `/` menu, Tab runs the highlighted command instead)
|
|
58
|
+
- `Esc`: stop a running response (footer shows `esc stops` while busy); deny a pending approval/question
|
|
59
|
+
- `/`: open command autocomplete (typing a full command name collapses the menu to it)
|
|
60
|
+
- `Ctrl+O`: open the tool-output inspector (browse past tool calls; `↑`/`↓` select, `Enter` expands, `PgUp`/`PgDn` scroll, `Esc` closes)
|
|
61
|
+
- `Ctrl+P`: command palette (searchable, same registry)
|
|
62
|
+
- `Ctrl+C`: cancel the running turn; exit when idle
|
|
63
|
+
- `PgUp`/`PgDn`: scroll the transcript (`End` follows latest)
|
|
64
|
+
- `↑`/`↓`: recall past prompts; `Ctrl+J` inserts a newline (`Enter` always sends)
|
|
65
|
+
- `y` once, `a` always, `t` trust all, `n` deny: answer write/shell approval prompts in normal mode
|
|
66
|
+
|
|
67
|
+
## Status line
|
|
68
|
+
|
|
69
|
+
Format when idle: provider/model │ token │ cwd[` : `branch] │ reasoning │ mode (`+trust` when session trust is on, hidden in plan mode) │ goal (only while a goal is live: `goal: <objective> [active|paused]`, truncated to fit — it yields first under width pressure and never displaces other segments). While busy: live activity │ elapsed │ token │ reasoning │ mode │ goal (same goal segment when live) │ `esc stops` (+`waiting…` / `waiting approval` flags).
|
|
70
|
+
|
|
71
|
+
Token segment (`src/context-windows.ts`):
|
|
72
|
+
|
|
73
|
+
- `token: n/a`: no usage reported yet. Never estimated
|
|
74
|
+
- `token: (P%) NK`: known context window. NK is cumulative session spend in K (`round(total/1024)`). P% is current context load over the verified window (last POST input tokens including prefix-cache reads, else the 4 chars/token estimate)
|
|
75
|
+
- `token: NK`: model has no verified window. Bare total only
|
|
76
|
+
- `token: 0K` / `token: (0%) 0K`: zero usage, with/without a known window
|
|
77
|
+
|
|
78
|
+
## Reasoning and streaming
|
|
79
|
+
|
|
80
|
+
Tokens, tool activity, and phase status render live. Reasoning streams in its own dim block above the answer draft (transient). Tool calls execute locally and results feed back into the loop with no step cap by default (optional cap via `ATOM_MAX_TOOL_STEPS`, clamped 5-100).
|
|
81
|
+
|
|
82
|
+
See [Sessions](sessions.md), [Compaction](compaction.md), and [Permissions](permissions.md) for the systems behind these commands.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Compaction and Token Display
|
|
2
|
+
|
|
3
|
+
Claude-Code and opencode-style context management (`src/compact.ts`, `src/context-windows.ts`, `src/context-manager.ts`). History budgets derive from the model window (see [Configuration](configuration.md)); compaction mechanics below are unchanged.
|
|
4
|
+
|
|
5
|
+
## Auto-compact
|
|
6
|
+
|
|
7
|
+
Triggers at about 83% of the model verified context window:
|
|
8
|
+
|
|
9
|
+
- Threshold fraction default `0.83`
|
|
10
|
+
- Env `ATOM_COMPACT_PCT` is a percent (example `"83"`), clamped 50-95. Invalid or unset falls back to default
|
|
11
|
+
- Load metric: last POST reported input-side tokens (prompt counts normalized to include exclusive prefix-cache counters like Anthropic's `cache_read`/`cache_creation`) when available, else the 4 chars/token estimate of sent history chars
|
|
12
|
+
- No verified window for the model: never auto-compacts, never invents a window
|
|
13
|
+
|
|
14
|
+
## Manual compact
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
/compact [focus text]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Summarizes older turns into one summary with tools disabled and a 4096 output cap. Optional focus text narrows the summary (example `/compact focus auth flow`).
|
|
21
|
+
|
|
22
|
+
Mechanics:
|
|
23
|
+
|
|
24
|
+
- Split history (after system) into head plus retained newest tail of whole user-turns up to about 20000 estimated tokens (chars/4)
|
|
25
|
+
- Tool outputs in the tail capped at 2000 chars each
|
|
26
|
+
- Always keeps at least the newest turn. When everything fits but there is more than one turn, keeps only the newest turn in the tail so manual compact still has an older turn to summarize
|
|
27
|
+
- Summary instruction uses fixed headings (omit a section only when empty): Objective, Important Details, Work State (Completed, Active, Blocked), Next Move, Relevant Files
|
|
28
|
+
- Rules line: no tools available for the request, answer with summary text only
|
|
29
|
+
- Swap is atomic plus saved. Size-overflow truncates head to budget once (drops oldest half of user-turns, preserves pairing) and retries once, then suggests `/clear`. Other failures throw with history untouched
|
|
30
|
+
- Touched files: the compacted summary records the head's read/modified paths (collected from the committed tool calls the loop already recorded — no new tracking), appended as a `Touched files:` block (`Read:` / `Modified:` lines). Over-budget lists shrink oldest-first to the summary budget instead of failing compaction; the model text is never cut. `/resume` surfaces the stored block verbatim
|
|
31
|
+
- Goal block: when a goal is live, compaction appends a `Goal:` line (objective, state, cumulative stats, open todos) to the summary as context for the continued run. Restore still rides the persisted session record (`goal` field, see [Sessions](sessions.md)) — the `Goal:` text keeps the objective visible in history without re-exploring the tree
|
|
32
|
+
|
|
33
|
+
Thrash guard: 3 auto-compactions without the load dropping below threshold disables auto for the session (manual `/compact` still works and resets the counter on success).
|
|
34
|
+
|
|
35
|
+
## Token display
|
|
36
|
+
|
|
37
|
+
Exact footer format (`formatTokenSegment`):
|
|
38
|
+
|
|
39
|
+
- `token: n/a`: no usage reported yet. Never estimated
|
|
40
|
+
- `token: (P%) NK`: known window. NK is `round(total/1024)` plus `K` from cumulative session spend (`total_tokens`, else `prompt_tokens` plus `completion_tokens`). P is `round(100*load/window)` from current context load, not cumulative spend
|
|
41
|
+
- `token: NK`: unknown window. Bare total only
|
|
42
|
+
- Zero usage with known window: `token: (0%) 0K`. Without one: `token: 0K`
|
|
43
|
+
|
|
44
|
+
Cumulative spend keeps growing after compaction, so it must not drive P. Load does.
|
|
45
|
+
|
|
46
|
+
## Verified windows
|
|
47
|
+
|
|
48
|
+
Curated per-model map in `src/context-windows.ts` (build-time vendor docs, comments cite sources). Missing models render without a percent. Examples from the map: DeepSeek V4 family 1M, Kimi K2.6 256K, GLM-5.2 1M, GPT-6/GPT-5.6 1.05M, Gemini 3 family about 1M. Read the file for the full table; do not assume a window for unlisted models.
|
|
49
|
+
|
|
50
|
+
Related: [Sessions](sessions.md) for persistence, [CLI](cli.md) for the footer, [Configuration](configuration.md) for `ATOM_COMPACT_PCT`.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
All knobs, files, and prompt layering in one place. Env vars win over stored keys. Nothing here requires code changes.
|
|
4
|
+
|
|
5
|
+
## Environment variables
|
|
6
|
+
|
|
7
|
+
Template lives in `.env.example`. Never commit a real key.
|
|
8
|
+
|
|
9
|
+
| Variable | Purpose | Default |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `KILO_API_KEY` | Kilo key (optional — free models work anonymously). Wins over stored Kilo key | none (Kilo free models still chat; `/provider` shows the key as optional) |
|
|
12
|
+
| `OPENCODE_ZEN_API_KEY` | Zen key. Wins over stored zen key | none (TUI still starts, chat errors inline with a `/provider` pointer) |
|
|
13
|
+
| `OPENCODE_ZEN_MODEL` | Zen model id | `deepseek-v4-pro` |
|
|
14
|
+
| `OPENCODE_ZEN_ENDPOINT` | Zen endpoint override | `https://opencode.ai/zen/v1/chat/completions` |
|
|
15
|
+
| `OPENCODE_AGENTS_PATH` | Override for the AGENTS.md appended to the system prompt | `<cwd>/AGENTS.md` |
|
|
16
|
+
| `OPENAI_API_KEY` | OpenAI key (env wins over stored) | none |
|
|
17
|
+
| `ANTHROPIC_API_KEY` | Anthropic key | none |
|
|
18
|
+
| `DEEPSEEK_API_KEY` | DeepSeek key | none |
|
|
19
|
+
| `MISTRAL_API_KEY` | Mistral key | none |
|
|
20
|
+
| `GEMINI_API_KEY` / `GOOGLE_API_KEY` | Gemini key (either accepted, first non-empty wins) | none |
|
|
21
|
+
| `ATOM_COMPACT_PCT` | Auto-compact percent, clamped 50-95 | `83` (about 83% of verified window) |
|
|
22
|
+
| `ATOM_MAX_TOOL_STEPS` | Optional cap on tool rounds per turn, clamped 5-100 | uncapped |
|
|
23
|
+
| `ATOM_HOME` | Override home for `~/.atom/` files (auth, session) | OS homedir |
|
|
24
|
+
| `ATOM_TELEMETRY` | Local observability recording (`0`/`false`/`no`/`off` disables; `1`/`true`/`yes`/`on` forces on) | on (wins over `atom.json`) |
|
|
25
|
+
| `ATOM_TELEMETRY_PORT` | Pinned port for the observability webUI (`atom --serve`; `--port` wins over this) | ephemeral (OS-assigned, printed on start) |
|
|
26
|
+
| `ATOM_EXTENSIONS` | Extra extension directory for discovery (project, global, then this; see [Extensions](extensions.md)) | none |
|
|
27
|
+
| `ATOM_OLLAMA_URL` | Ollama base URL override for local discovery | `http://localhost:11434` |
|
|
28
|
+
| `ATOM_LMSTUDIO_URL` | LM Studio base URL override for local discovery | `http://localhost:1234` |
|
|
29
|
+
| `ATOM_LLAMACPP_URL` | llama.cpp base URL override for local discovery | `http://localhost:8080` |
|
|
30
|
+
|
|
31
|
+
`openai-compatible` uses stored key plus baseURL only. No env vars.
|
|
32
|
+
|
|
33
|
+
## atom.json config file
|
|
34
|
+
|
|
35
|
+
Template lives in `atom.example.json`. Two levels, merged per key (project wins over global):
|
|
36
|
+
|
|
37
|
+
- Project: `<cwd>/atom.json`
|
|
38
|
+
- Global: `~/.atom/atom.json` (`ATOM_HOME` overrides home)
|
|
39
|
+
|
|
40
|
+
Precedence overall: env vars > saved session picks (`/model`, `/provider`, `/effort`) > project `atom.json` > global `atom.json` > compiled defaults. So `atom.json` sets first-run and project defaults; a later explicit pick (saved each turn and on exit) still wins across restarts; env always wins.
|
|
41
|
+
|
|
42
|
+
| Key | Purpose | Range / values |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `provider` | First-run default provider (needs its key, except keyless Kilo/local) | known provider id |
|
|
45
|
+
| `model` | Default model id | non-empty string |
|
|
46
|
+
| `reasoningEffort` | Default reasoning effort | `auto`/`low`/`medium`/`high`/`max` (`default` still accepted as an alias for `auto`) |
|
|
47
|
+
| `maxToolSteps` | Tool rounds per turn | 5-100 (default 30) |
|
|
48
|
+
| `compactPct` | Auto-compact percent of verified window | 50-95 (default 83) |
|
|
49
|
+
| `network` | Webfetch SSRF policy: which network zones the model may retrieve | object with boolean `allowPublic` (default true), `allowLocalhost` (default true), `allowPrivate` (default false), `allowLinkLocal` (default false) |
|
|
50
|
+
| `telemetry` | Local observability recording (see [Observability](observability.md)) | `{enabled?: boolean}` (default on; `ATOM_TELEMETRY=0` wins) |
|
|
51
|
+
| `extensions` | Extension enable/disable patterns by name (see [Extensions](extensions.md); CLI `--enable-extension`/`--disable-extension` win over this) | `{enabled?: string[], disabled?: string[]}` (default load all; `disabled` wins over `enabled`) |
|
|
52
|
+
|
|
53
|
+
Missing files are normal and silent. Unknown keys are ignored; invalid values fall back per key with warnings surfaced in `/context`. Reads are fresh per call, so edits apply without restart. Never commit keys here (there are no key fields — keys stay in env/`auth.json`).
|
|
54
|
+
|
|
55
|
+
Example: open the LAN but keep cloud metadata closed:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{ "network": { "allowPrivate": true } }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Context budget (`src/context-manager.ts`)
|
|
62
|
+
|
|
63
|
+
The `ContextManager` is the single place answering: how much context is available, how much is used, should we compact. History allowance derives from the model's verified window:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
available history = window − system prompt − tool definitions
|
|
67
|
+
− output reserve (4096 tok) − safety margin (5%)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The allowance is informational only: history is never truncated — there are no message/char caps (`ATOM_MAX_HISTORY_*` env vars and `maxHistory*` config keys no longer exist; if present in `atom.json` they are ignored as unknown keys). Compaction is the only pressure valve.
|
|
71
|
+
|
|
72
|
+
- Known-window models (256K, 1M, …) use their real windows — no fixed 200K-char assumption.
|
|
73
|
+
- Accounting is incremental: the `ContextLedger` (`trackHistory` in `src/context-manager.ts`) keeps exact running counters (messages, chars, est. tokens, system/tool chars, per-role counts) across pushes, splices, and replacements — per-step reads are O(1) instead of rescanning history. `verifyLedger` diffs counters against an independent scan (tests enforce it; exact provider-reported usage stays separate in the token totals).
|
|
74
|
+
- See `/context` for the live per-source breakdown and [Compaction](compaction.md) for the trigger mechanics.
|
|
75
|
+
|
|
76
|
+
## Auth file
|
|
77
|
+
|
|
78
|
+
`~/.atom/auth.json` (`ATOM_HOME` overrides home):
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"version": 1,
|
|
83
|
+
"providers": {
|
|
84
|
+
"<id>": { "apiKey": "...", "baseURL?": "..." }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`0600` on POSIX, best-effort on Windows. Missing or corrupt loads as empty auth. Save via `/provider` paste flow; resolution is env-first per provider. See [Providers](providers.md).
|
|
90
|
+
|
|
91
|
+
## Session file
|
|
92
|
+
|
|
93
|
+
`~/.atom/session.json`, version 1, atomic temp-plus-rename saves, `0600` POSIX. See [Sessions](sessions.md).
|
|
94
|
+
|
|
95
|
+
## AGENTS.md and system prompt
|
|
96
|
+
|
|
97
|
+
Final system prompt is two layers (`src/system.ts`, `src/zen.ts`):
|
|
98
|
+
|
|
99
|
+
```text
|
|
100
|
+
<base one-liner from src/system.ts> + "\n\n" + <repo AGENTS.md>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
- Base identity: long-horizon coding agent loop (explore, plan with todowrite for 3 or more steps, implement, verify with tests and typecheck, report with evidence)
|
|
104
|
+
- Repo overlay: `AGENTS.md` in cwd, or `OPENCODE_AGENTS_PATH` override. Capped at 12KB
|
|
105
|
+
- To change bot identity, edit the one-liner. To add project instructions, edit `AGENTS.md`
|
|
106
|
+
|
|
107
|
+
ATOM loads the project `AGENTS.md` at startup so it knows tools, rules, and permission model. This repo own instructions live in `AGENTS.md` at the root.
|
|
108
|
+
|
|
109
|
+
## Context windows
|
|
110
|
+
|
|
111
|
+
Curated map in `src/context-windows.ts`. Drives the footer percent and auto-compact threshold. Never invented for unlisted models. See [Compaction](compaction.md).
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Development
|
|
2
|
+
|
|
3
|
+
Setup, scripts, structure, and verification for contributors. Commands below come from `package.json` scripts.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
npm start # run the TUI from source (needs a TTY)
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Build output goes to `dist/` (`atom` runs `dist/cli.js`). `dist/` is gitignored and shipped in the tarball.
|
|
13
|
+
|
|
14
|
+
## Scripts
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm start # tsx src/cli.tsx
|
|
18
|
+
npm test # vitest run (fully mocked, never hits live APIs)
|
|
19
|
+
npm run typecheck # tsc --noEmit
|
|
20
|
+
npm run build # tsc -p tsconfig.build.json (src -> dist)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Tests use `"test-key"` placeholders. Never paste a real key into fixtures, logs, or commits.
|
|
24
|
+
|
|
25
|
+
## Project structure
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
.
|
|
29
|
+
├── src/
|
|
30
|
+
│ ├── cli.tsx # entry: --help/--dashboard/--serve, always starts TUI (missing key guides to /provider)
|
|
31
|
+
│ ├── App.tsx # Ink TUI: transcript, pickers (/model /provider /effort), modes, status line
|
|
32
|
+
│ ├── context-windows.ts # curated per-model context windows + `token: (P%) NK` format
|
|
33
|
+
│ ├── compact.ts # context compaction: load/trigger math, split, summary POST (tools off, 4096 cap)
|
|
34
|
+
│ ├── zen.ts # provider dispatch: streaming SSE, retries, agentic-loop wrappers (shared core in src/agent/loop.ts)
|
|
35
|
+
│ ├── providers.ts # 8 remote providers + 3 local runtimes (kind/endpoint/env/default + fallback models; kilo default)
|
|
36
|
+
│ ├── kilo.ts # Kilo Gateway: live catalog parsing, :free detection, TTL cache, error normalization
|
|
37
|
+
│ ├── auth.ts # ~/.atom/auth.json store (env wins, 0600 POSIX)
|
|
38
|
+
│ ├── adapters.ts # anthropic/gemini translation + SSE + models-list parsing + key validation
|
|
39
|
+
│ └── tools.ts # 13 local tool executors + function schemas
|
|
40
|
+
├── dist/ # `npm run build` output (`atom` runs dist/cli.js; gitignored, shipped in the tarball)
|
|
41
|
+
├── tests/ # fully mocked (never live APIs; keys use "test-key")
|
|
42
|
+
├── AGENTS.md # the agent's own instructions (loaded at startup)
|
|
43
|
+
├── tsconfig.build.json # build-only config (src -> dist)
|
|
44
|
+
└── .env.example # env template (never commit a real key)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Full source adds: `env-block.ts`, `permissions.ts`, `policy.ts`, `rollback.ts`, `session.ts`, `sessions.ts`, `goal.ts`, `agent/goal-evaluator.ts`, `extensions.ts`, `extension-commands.ts`, `extension-ui.ts`, `project-trust.ts`, `skills.ts`, `snapshots.ts`, `system.ts`, `config.ts`, `scheduler.ts`, `context-manager.ts`, `prompt-cache.ts`, `local-discovery.ts`, `telemetry.ts` (local observability recorder + store), `telemetry-dashboard.ts` (self-contained HTML drill-down), `telemetry-server.ts` (loopback-only live webUI + read-only JSON API), `agent/` (shared loop core, gates, types), `tools/` (per-tool executors + registry, including `custom.ts`, `intercept.ts`, `overrides.ts`, `provider-hooks.ts`, `compaction-hooks.ts`), `ui/` (transcript, diff stack, panels, pickers, status line). Tests live in `tests/` (including `app`, `agent`, `loop-core`, `permissions`, `skills`, `compact`, `session`, `adapters`, `providers`, `kilo`, `tools`, `telemetry`, `diff`, `status-bar`, `slash` suites).
|
|
48
|
+
|
|
49
|
+
## Verification standard
|
|
50
|
+
|
|
51
|
+
Done means tests and typecheck pass, or the blocker is named with evidence. Minimum for a change:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm test
|
|
55
|
+
npm run typecheck
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Add or update tests for behavior changes. A fix without a test that would have caught it is incomplete. Keep blast radius small: match existing patterns, remove dead code and debug leftovers, handle errors and edge cases explicitly.
|
|
59
|
+
|
|
60
|
+
## Agent workflow in this repo
|
|
61
|
+
|
|
62
|
+
The repo `AGENTS.md` defines the loop the agent follows: read before edit, 30 tool rounds per turn by default, todowrite list for 3 or more steps with exactly one `in_progress`, verify every change with the suite. Issues live as local markdown under `.scratch/` (see [Issue tracker](agents/issue-tracker.md)).
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Extensions
|
|
2
|
+
|
|
3
|
+
Write a local file, trust the project, restart — your code runs inside ATOM with the full ExtensionAPI. Three copy-paste samples under `examples/extensions/` prove each surface; the guide names them, the tests load them.
|
|
4
|
+
|
|
5
|
+
## Install location (global vs project)
|
|
6
|
+
|
|
7
|
+
| Scope | Directory | Trust |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Global | `~/.atom/extensions/` (`ATOM_HOME` overrides home) | Implicitly trusted — user-owned, like your own config |
|
|
10
|
+
| Project | `<cwd>/.atom/extensions/` | Gated — never executes until the project is trusted |
|
|
11
|
+
| Explicit | `ATOM_EXTENSIONS` env (delimiter-separated paths) | Gated, like project scope |
|
|
12
|
+
|
|
13
|
+
Each scope entry is a `.ts`, `.js`, `.mjs`, or `.cjs` file, or a subdirectory holding an `index.ts`/`index.js`/`index.mjs`/`index.cjs` (or a `package.json` with an `atom.extensions` manifest listing entry files). Dotfiles are skipped. Order is project, global, explicit.
|
|
14
|
+
|
|
15
|
+
## Minimal file shape (factory export)
|
|
16
|
+
|
|
17
|
+
One file, one factory — CJS or TS, both load same-process via jiti:
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
// hello.js — put in ~/.atom/extensions/ (trusted) or <cwd>/.atom/extensions/ (gated)
|
|
21
|
+
module.exports = function (api) {
|
|
22
|
+
api.notify("hello extension loaded");
|
|
23
|
+
};
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
// hello.ts — same contract, typed
|
|
28
|
+
import type { ExtensionAPI } from "../../src/extensions.js";
|
|
29
|
+
export default function (api: ExtensionAPI) {
|
|
30
|
+
api.notify("hello extension loaded");
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The export must be a function (or a default-exported function). Anything else is a recorded load error, not a crash — `loadExtensions` never throws; per-extension failures land on `runtime.errors` and the rest still load.
|
|
35
|
+
|
|
36
|
+
## Trust prompt expectation
|
|
37
|
+
|
|
38
|
+
With a project-scope extension present and the project not yet trusted, startup asks once via the question modal:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
This project contains 1 extension(s) (hello) that run unsandboxed with your full user privileges — they can read/write your files and run commands as you. Load them?
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Answers are `Trust and load` (persists a per-project grant in `~/.atom/trusted-projects.json`) and `Keep disabled` (nothing executes, a visible skipped notice posts, asks again next boot). Esc declines. Extension code runs with your full privileges — no sandbox — so read anything you install first.
|
|
45
|
+
|
|
46
|
+
## Enable, disable, lockdown
|
|
47
|
+
|
|
48
|
+
- `--enable-extension <glob>` (repeatable): allowlist — only matching names load, the rest skip as `not-enabled`.
|
|
49
|
+
- `--disable-extension <glob>` (repeatable): wins over enable; matches skip as `disabled`.
|
|
50
|
+
- `atom.json` `extensions: { enabled: [...], disabled: [...] }`: same patterns in config; CLI wins over config when set; project config wins over global. See [Configuration](configuration.md).
|
|
51
|
+
- `--no-extensions` (`--lockdown` alias): boots with zero third-party extensions — project, global, and explicit paths alike skip as `lockdown`. Builtins are untouched.
|
|
52
|
+
|
|
53
|
+
Precedence, highest first: lockdown > untrusted-project > disabled > enabled > load.
|
|
54
|
+
|
|
55
|
+
## How to see it loaded
|
|
56
|
+
|
|
57
|
+
Startup posts one info line when anything loaded or failed:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
(extensions: 1 loaded (hello))
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Skipped extensions stay visible with the fix:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
(extensions: 1 skipped (hello) — the project is not trusted; trust the project when asked on next startup to load them)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Then confirm the surface: `/tools` lists registered custom tools, the command palette (`Ctrl+P`) and the `/` menu list registered slash commands, the status line shows contributed segments.
|
|
70
|
+
|
|
71
|
+
## Gallery (copy-paste samples)
|
|
72
|
+
|
|
73
|
+
Single source of truth: the files under `examples/extensions/`. The guide excerpts them; the tests (`tests/extension-gallery.test.ts`) load the checked-in files through the real `loadExtensions` path — never a mock API, never a copy.
|
|
74
|
+
|
|
75
|
+
**`01-audit-gate.js`** — destructive-command audit gate via `onBeforeToolCall`. Returning `{ block: reason }` vetoes the call: the reason commits as the model-visible result, approval is skipped, the tool never runs.
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
api.onBeforeToolCall(({ name, args }) => {
|
|
79
|
+
if (name !== "bash") return;
|
|
80
|
+
const command = String(args?.command ?? "");
|
|
81
|
+
const DESTRUCTIVE = ["rm -rf /", "rm -rf ~", "rm -rf .", "mkfs", ":(){:|:&};:"];
|
|
82
|
+
if (DESTRUCTIVE.some((sig) => command.includes(sig))) {
|
|
83
|
+
return {
|
|
84
|
+
block:
|
|
85
|
+
"destructive shell commands need explicit confirmation — " +
|
|
86
|
+
"narrow the command or confirm it with the user first",
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**`02-notes-tool.js`** — model-callable tool via `registerTool` with a parameters schema and `execute`. Bad args are an inline `Error: invalid call: ...` and the implementation never runs; the tool dispatches through the shared loop like a builtin.
|
|
93
|
+
|
|
94
|
+
```js
|
|
95
|
+
api.registerTool({
|
|
96
|
+
name: "gallery_notes",
|
|
97
|
+
description: "Save a short note and read it back. Use it to remember user preferences across the turn.",
|
|
98
|
+
parameters: {
|
|
99
|
+
type: "object",
|
|
100
|
+
properties: { text: { type: "string" } },
|
|
101
|
+
required: ["text"],
|
|
102
|
+
additionalProperties: false,
|
|
103
|
+
},
|
|
104
|
+
execute: async (args) => {
|
|
105
|
+
notes.push(String(args.text));
|
|
106
|
+
return `saved note #${notes.length}: ${notes[notes.length - 1]}`;
|
|
107
|
+
},
|
|
108
|
+
requireApproval: false,
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**`03-custom-command.js`** — real slash command via `registerCommand` with a modal dialog plus transcript posts. The workflow logic is a pure helper (`summarizeChoice`) so the dialog flow is testable headless — tests drive the command with a stub `askUser` and unit-test the helper directly.
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
api.registerCommand({
|
|
116
|
+
name: "gallery-plan",
|
|
117
|
+
description: "Pick a deploy target and post the plan.",
|
|
118
|
+
handler: async (ctx) => {
|
|
119
|
+
const choice = await ctx.askUser("Which environment?", ["staging", "prod"]);
|
|
120
|
+
const plan = summarizeChoice(choice, ctx.args);
|
|
121
|
+
ctx.say(plan);
|
|
122
|
+
return `plan posted for ${choice}`;
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## API surface (`src/extensions.ts`)
|
|
128
|
+
|
|
129
|
+
Exact `ExtensionAPI` methods — nothing else exists:
|
|
130
|
+
|
|
131
|
+
| Method | What it does |
|
|
132
|
+
|---|---|
|
|
133
|
+
| `on(event, handler)` | `session_start` / `session_shutdown` lifecycle |
|
|
134
|
+
| `registerTool(def)` | New model-callable tool (`name`, `description`, `parameters`, `execute`, `requireApproval?`) |
|
|
135
|
+
| `overrideTool(def)` | Audited, reversible builtin shadow (deny a subset or `ctx.passthrough`) |
|
|
136
|
+
| `addPromptHint(hint)` | Model-facing guidance appended under "Extension hints" |
|
|
137
|
+
| `registerCommand(def)` | Real `/name args` slash command (builtins always win name collisions) |
|
|
138
|
+
| `onBeforeToolCall(handler)` | Rewrite `{ args }` or veto `{ block: reason }` pre-validation/pre-approval |
|
|
139
|
+
| `onAfterToolCall(handler)` | Patch committed results (`string` or `{ content }`) |
|
|
140
|
+
| `onBeforeSwitch(handler)` | Veto a pending session switch (throws fail open) |
|
|
141
|
+
| `onTransformContext(handler)` | Replace the per-POST message array |
|
|
142
|
+
| `onBeforeRequest(handler)` | Replace payload / mutate headers per POST |
|
|
143
|
+
| `onAfterResponse(handler)` | Observe-only provider response hook |
|
|
144
|
+
| `onBeforeCompact(handler)` | Veto compaction or replace the summary |
|
|
145
|
+
| `getSessionState()` / `setSessionState(value)` | Per-session namespaced state (durable, JSON-serializable) |
|
|
146
|
+
| `isProjectTrusted()` | Whether this load is trusted (degrade gracefully when false) |
|
|
147
|
+
| `setStatusSegment(text)` | One status-bar slot per extension (upsert by owner) |
|
|
148
|
+
| `setWidget(def)` | Panel widget (`placement: "panel"`, keyed by owner + id) |
|
|
149
|
+
| `notify(message)` | Transient `(name) message` transcript line (staged queue caps at 100, drop-oldest) |
|
|
150
|
+
| `promptUser(question, options?, allowCustom?)` | Modal dialog; rejects headless, during activation, or while one is open |
|
|
151
|
+
|
|
152
|
+
Stores behind the API: `src/tools/custom.ts`, `intercept.ts`, `overrides.ts`, `provider-hooks.ts`, `compaction-hooks.ts`, `src/extension-commands.ts`, `src/extension-ui.ts`, `src/project-trust.ts`.
|
|
153
|
+
|
|
154
|
+
## Rules that bite
|
|
155
|
+
|
|
156
|
+
- **Staged activation is atomic.** Validation runs eagerly; a factory that throws (or a duplicate/colliding name at commit) leaves zero registrations behind — nothing half-loads.
|
|
157
|
+
- **Stale generation.** Every session replacement invalidates handed-out APIs; captured handles throw loudly, event handlers always receive a fresh API.
|
|
158
|
+
- **Approval fail-closed.** Custom tools require approval by default; opt out only with `requireApproval: false` for pure side-effect-free helpers.
|
|
159
|
+
- **Serial by default.** Custom tools carry no scheduler metadata and run as serial singletons; `executionMode: "sequential"` forces the whole sibling batch one-at-a-time.
|
|
160
|
+
- **Dialogs are single-flight and interactive-only.** A second request rejects, headless rejects, activation-time prompts reject — never a hang. Command `askUser` works because commands run outside activation with the TUI fulfilling the modal.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
Fastest path from zero to chatting with an agent that can read, edit, and run your code.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Node.js `>=18` (see `engines` in `package.json`)
|
|
8
|
+
- No API key required to start: the default provider is Kilo Gateway, whose free models work anonymously
|
|
9
|
+
- A TTY for `npm start` (the TUI needs an interactive terminal)
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
Global install gives you the `atom` binary:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm i -g atom-agent
|
|
17
|
+
atom
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or run from source:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## First run
|
|
27
|
+
|
|
28
|
+
1. Just start it — no key needed:
|
|
29
|
+
|
|
30
|
+
```powershell
|
|
31
|
+
npm start
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
2. ATOM selects Kilo automatically, discovers its live model catalog, and starts on the free routing model (`kilo-auto/free`) when no Kilo key is configured. Open `/model` to see the discovered models (free ones carry a `(free)` badge) and pick one.
|
|
35
|
+
3. Type `/` to see every command. Type `/provider` to paste a Kilo key once (optional — unlocks the full catalog) or to switch to another provider.
|
|
36
|
+
|
|
37
|
+
No key at all: the TUI still starts, and Kilo's free models chat immediately. Providers that need a key error inline and point at `/provider` instead of posting. Nothing is posted without a usable route.
|
|
38
|
+
|
|
39
|
+
To use a keyed provider instead (e.g. OpenCode Zen), get a key at `https://opencode.ai/auth` and set it for the session (PowerShell shown; use `export` on POSIX):
|
|
40
|
+
|
|
41
|
+
```powershell
|
|
42
|
+
$env:OPENCODE_ZEN_API_KEY="sk-your-key"
|
|
43
|
+
npm start
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Quickstart path
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
prerequisites
|
|
50
|
+
-> npm install
|
|
51
|
+
-> npm start (Kilo free model, no key)
|
|
52
|
+
-> /model to pick a discovered model, ask something about your repo
|
|
53
|
+
-> optional: KILO_API_KEY (or paste via /provider) for the full Kilo catalog
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Expected result: streaming answer with live tool activity and a status line showing provider, model, token usage, reasoning effort, and mode.
|
|
57
|
+
|
|
58
|
+
## Next steps
|
|
59
|
+
|
|
60
|
+
- [CLI and TUI](cli.md) for slash commands and keyboard control
|
|
61
|
+
- [Providers and Models](providers.md) to switch off Kilo, add a Kilo key, or use a local OpenAI-compatible server
|
|
62
|
+
- [Configuration](configuration.md) for all env knobs and the auth file
|
|
63
|
+
- [Troubleshooting](troubleshooting.md) if the first run fails
|