@abaigram/abaikit 0.0.0-stage → 0.1.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.
Files changed (70) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +15 -2
  3. package/abai/identity.md +1 -0
  4. package/abai/learnabai.md +474 -0
  5. package/abai/use.md +1 -0
  6. package/abaigram.yaml +208 -0
  7. package/dist/abaify.d.ts +68 -0
  8. package/dist/abaify.d.ts.map +1 -0
  9. package/dist/abaify.js +310 -0
  10. package/dist/abaify.js.map +1 -0
  11. package/dist/abaigram.d.ts +18 -0
  12. package/dist/abaigram.d.ts.map +1 -0
  13. package/dist/abaigram.js +153 -0
  14. package/dist/abaigram.js.map +1 -0
  15. package/dist/app.d.ts +19 -0
  16. package/dist/app.d.ts.map +1 -0
  17. package/dist/app.js +29 -0
  18. package/dist/app.js.map +1 -0
  19. package/dist/bin.d.ts +45 -0
  20. package/dist/bin.d.ts.map +1 -0
  21. package/dist/bin.js +274 -0
  22. package/dist/bin.js.map +1 -0
  23. package/dist/check.d.ts +119 -0
  24. package/dist/check.d.ts.map +1 -0
  25. package/dist/check.js +416 -0
  26. package/dist/check.js.map +1 -0
  27. package/dist/command.d.ts +41 -0
  28. package/dist/command.d.ts.map +1 -0
  29. package/dist/command.js +179 -0
  30. package/dist/command.js.map +1 -0
  31. package/dist/index.d.ts +5 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +5 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/io.d.ts +12 -0
  36. package/dist/io.d.ts.map +1 -0
  37. package/dist/io.js +20 -0
  38. package/dist/io.js.map +1 -0
  39. package/dist/learnabai.d.ts +60 -0
  40. package/dist/learnabai.d.ts.map +1 -0
  41. package/dist/learnabai.js +197 -0
  42. package/dist/learnabai.js.map +1 -0
  43. package/dist/new.d.ts +26 -0
  44. package/dist/new.d.ts.map +1 -0
  45. package/dist/new.js +87 -0
  46. package/dist/new.js.map +1 -0
  47. package/dist/repo.d.ts +99 -0
  48. package/dist/repo.d.ts.map +1 -0
  49. package/dist/repo.js +482 -0
  50. package/dist/repo.js.map +1 -0
  51. package/dist/run.d.ts +6 -0
  52. package/dist/run.d.ts.map +1 -0
  53. package/dist/run.js +47 -0
  54. package/dist/run.js.map +1 -0
  55. package/dist/subject.d.ts +15 -0
  56. package/dist/subject.d.ts.map +1 -0
  57. package/dist/subject.js +53 -0
  58. package/dist/subject.js.map +1 -0
  59. package/dist/template-ts.d.ts +21 -0
  60. package/dist/template-ts.d.ts.map +1 -0
  61. package/dist/template-ts.js +322 -0
  62. package/dist/template-ts.js.map +1 -0
  63. package/dist/version.d.ts +3 -0
  64. package/dist/version.d.ts.map +1 -0
  65. package/dist/version.js +3 -0
  66. package/dist/version.js.map +1 -0
  67. package/examples/hello/abai/identity.md +1 -0
  68. package/examples/hello/abaigram.yaml +24 -0
  69. package/examples/hello/hello.ts +18 -0
  70. package/package.json +40 -5
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Joon Hwa Jung
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,16 @@
1
- # Temporary Holding Version
1
+ # @abaigram/abaikit
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The abai authoring tool, itself an abaigram. A coding agent uses it to
4
+ make a program an abaigram under the contract, `spec/abaigrammar.md` in
5
+ the [abai repository](https://github.com/jjbits/abai). Installed with
6
+ `npm install --save-dev @abaigram/abaikit`, the command is `abaikit`.
7
+
8
+ - `abaikit learnabai` prints the guide the agent follows; `--skill`
9
+ installs it as a Claude Code skill.
10
+ - `abaikit check <repo>` verifies a repository's conformance and its
11
+ level; it needs no model.
12
+ - `abaikit new <name> --lang ts` creates a fresh abaigram.
13
+ - `abaikit abaify <repo>` retrofits an existing repository, adding and
14
+ never removing.
15
+ - `abaikit run <repo> -- ARGS` starts the repository's program.
16
+ - `abaikit abai ...` is the standard agent entry of abaikit itself.
@@ -0,0 +1 @@
1
+ You are the agent fused into abaikit, the abai authoring tool. You help a person create an abaigram, retrofit an existing repository into one, and verify conformance. You change a repository only through the repo.* capabilities, which add and never remove; you say why in every act; and you run check before you call anything done.
@@ -0,0 +1,474 @@
1
+ # learnabai: abai for a coding agent
2
+
3
+ abaigrammar {{abaigrammar}} · abai stub {{stub}} · abaikit {{abaikit}} · TypeScript
4
+
5
+ You are reading this because someone wants a program turned into an
6
+ abaigram, or a new one made, and you are the agent doing it. Read section
7
+ 1 once. Follow section 5 step by step; every step ends in a command that
8
+ proves it. Keep sections 2 and 8 at hand while you edit. `abaikit
9
+ learnabai --section <id>` prints one section; the ids are in the headings.
10
+
11
+ ## 1. What an abaigram is (what)
12
+
13
+ An abaigram is an ordinary program that includes the abai library (the
14
+ "stub") and thereby carries an agent: the agent ships with the program,
15
+ can run at install and during use, and observes and steers the program
16
+ only through channels the program declares. The contract is
17
+ `abaigrammar.md`; this guide is its TypeScript instantiation in practice.
18
+
19
+ Two halves, one boundary. The stub lives in the program. The harness is
20
+ the agent's runtime: a model, a tool set, a user channel. The boundary is
21
+ a function call inside the process (turns mode) or a local socket between
22
+ two processes (sidecar mode). It means the same thing either way.
23
+
24
+ Five channels, declared in a manifest the program builds in code:
25
+
26
+ - `events`: the program tells the agent something happened (push).
27
+ - `cells`: shared state the agent reads; a writable cell is a `knob` the
28
+ agent may set within its declared range.
29
+ - `capabilities`: functions the agent may call, each with a policy.
30
+ - `decisions`: the program stops and asks which way to go; every decision
31
+ has a default and a timeout, so the program never waits forever.
32
+ - `turns`: the program hands the agent a bounded moment to act.
33
+
34
+ Plus `lifecycle` (pause, resume, stop, restart, status: what a supervising
35
+ harness may do to the process) and `attention` (what wakes the agent, and
36
+ a budget on it).
37
+
38
+ Three modes. `turns`: one process, one thread, the agent runs only inside
39
+ a touchpoint; the simplest, the natural first rung for a command-line
40
+ program. `sidecar`: the harness is a separate process, attached through
41
+ a socket; the reference mode, the one with the whole lifecycle channel.
42
+ `thread` is in the contract but not in this instantiation yet. A manifest
43
+ declares the modes it supports; the first is the default; `ABAI_MODE`
44
+ overrides at startup.
45
+
46
+ Principles that bind everything you do:
47
+
48
+ 1. The program owns `main()`. The library is included; it wraps nothing
49
+ and replaces no entry point.
50
+ 2. The agent is invited: it acts through declared channels at declared
51
+ touchpoints and nowhere else.
52
+ 3. The program runs without the agent. No harness, a failed harness, a
53
+ missing model: the program is the plain program. Defaults everywhere.
54
+ 4. Declared, not discovered: the agent learns the program from the
55
+ manifest and its `doc` fields.
56
+ 5. Control has policy (`auto`, `confirm`, `forbid`) and leaves an audit
57
+ trail.
58
+ 6. It costs the program nothing it did not ask for: a detached channel
59
+ operation is a load or two; attached, nothing on the program's thread
60
+ allocates, locks or blocks except the touchpoints the program itself
61
+ placed.
62
+
63
+ How a person meets the agent: `<prog> abai` opens a session on the
64
+ terminal; `<prog> abai run -- ARGS` starts the program under the harness
65
+ with the whole lifecycle channel; `<prog> abai mcp` serves the agent's
66
+ tools to an MCP client such as Claude Code, whose own agent then is the
67
+ program's. All of that comes from a few inserted lines at the top of
68
+ `main()` (section 3).
69
+
70
+ ## 2. Declaring one in TypeScript (declare)
71
+
72
+ Install (section 5 has the exact command for this machine):
73
+
74
+ ```
75
+ npm install {{abai_spec}} {{harness_spec}}
76
+ ```
77
+
78
+ One module declares the abaigram and exports it. Everything below is
79
+ real API; copy what you need and delete the rest.
80
+
81
+ ```ts
82
+ // src/abai.ts
83
+ import { fileURLToPath } from "node:url";
84
+ import { createAbaigram } from "@abaigram/abai-stub";
85
+
86
+ export const app = createAbaigram(
87
+ {
88
+ name: "myprog", // the program's name; also the manifest's
89
+ entry: "node dist/main.js abai", // how the entry is reached: a runnable command line
90
+ modes: ["turns", "sidecar"], // supported; the first is the default
91
+ content: { identity: "abai/identity.md" }, // the prompts; identity is required
92
+ check: { run: "node dist/main.js --demo" }, // a short command that exercises the channels
93
+ cells: {
94
+ "queue.depth": { type: "int", access: "read", doc: "Jobs waiting." },
95
+ "worker.count": { // a knob: readwrite with a default and a range
96
+ type: "int", access: "readwrite", default: 4, range: [1, 64],
97
+ doc: "Active workers. The pool resizes at the next batch.",
98
+ },
99
+ },
100
+ events: {
101
+ "job.failed": {
102
+ payload: { job_id: { type: "string", max: 64 }, attempt: "int" },
103
+ wakes: "attempt gt 2", // "always", "never", or <field> eq|ne|gt|lt <json>
104
+ doc: "A job failed; past two attempts the agent is woken.",
105
+ },
106
+ },
107
+ capabilities: {
108
+ "job.retry": {
109
+ params: { job_id: "string" },
110
+ result: { ok: "bool" },
111
+ effect: "mutate", // "read" or "mutate"
112
+ policy: "confirm", // "auto" | "confirm" | "forbid"; mutate defaults to confirm
113
+ dispatch: "immediate", // run now. The default is "safepoint": the call waits for
114
+ // app.safepoint(), so a program that never calls safepoint()
115
+ // must declare "immediate", or the call stays pending and
116
+ // check never reaches L3
117
+ timeout: "30s",
118
+ example: { job_id: "job-0001" }, // check calls this; make it safe
119
+ doc: "Requeue a failed job once.",
120
+ handler: async ({ job_id }) => ({ ok: await retry(String(job_id)) }),
121
+ },
122
+ },
123
+ decisions: {
124
+ on_backlog: {
125
+ context: { depth: "int", workers: "int" },
126
+ options: ["scale_up", "shed_oldest", "wait"],
127
+ default: "wait",
128
+ timeout: "5s",
129
+ doc: "Asked when the backlog crosses the high-water mark.",
130
+ },
131
+ },
132
+ turns: {
133
+ end_of_batch: { timeout: "30s", doc: "After each batch. The agent may tune worker.count." },
134
+ },
135
+ lifecycle: {
136
+ pause: "cooperative", // "cooperative" | "os" | "none"
137
+ stop: { graceful: "10s", handler: () => shutdown() },
138
+ },
139
+ },
140
+ // the directory holding abaigram.yaml and abai/: one level up from src/abai.ts and from dist/abai.js;
141
+ // count the levels from the built file if the build nests deeper (dist/src/abai.js is two)
142
+ { root: fileURLToPath(new URL("..", import.meta.url)) },
143
+ );
144
+ ```
145
+
146
+ Using it from the program's own code, wherever the facts already are.
147
+ Obtain the handles once, at startup; `set`, `get` and `emit` are the cheap
148
+ calls. The import is in the repository's own style: `./abai.js` under
149
+ NodeNext (tsc resolves it to `abai.ts`), `./abai.ts` only where the project
150
+ runs or rewrites `.ts` imports.
151
+
152
+ ```ts
153
+ import { app } from "./abai.js";
154
+
155
+ const depth = app.cell<number>("queue.depth");
156
+ const workers = app.knob<number>("worker.count");
157
+ const failed = app.event("job.failed");
158
+
159
+ depth.set(queue.length); // one store, always cheap
160
+ const n = workers.get(); // the agent's setting, or the default
161
+ failed.emit({ job_id, attempt }); // nothing happens when no harness is attached
162
+ const choice = await app.decide<string>("on_backlog", { depth: queue.length, workers: n }); // "wait" when nobody answers
163
+ await app.turn("end_of_batch"); // returns at once when nobody is there
164
+ app.safepoint(); // where "safepoint" calls and a pause take effect
165
+ await app.attach(); // optional: ask for the agent now
166
+ ```
167
+
168
+ abai is ESM-only. In a CommonJS repository load it inside the async main:
169
+ `const { createAbaigram, runEntry } = await import("@abaigram/abai-stub");` (Node 22.12 and
170
+ later can also `require("@abaigram/abai-stub")`). Under `verbatimModuleSyntax` the imports
171
+ above are all value imports and need no change; a type you import, such as
172
+ `Abaigram`, needs `import type`.
173
+
174
+ Types: `int`, `float`, `bool`, `enum` (with `enum: [...]`), `string`,
175
+ `object` (with `fields`), `list` (with `items`); sized types carry `max`.
176
+ A schema field is a bare type name or `{ type, max, enum, fields, items,
177
+ nullable, doc }`. A knob is `access: "readwrite"` with a `default`; a
178
+ scalar knob lands in shared state, a sized one is delivered to
179
+ `app.knob(name).onChange(handler)` at a safepoint. Capabilities may also
180
+ be bound late: `app.capability("job.retry", handler)`.
181
+
182
+ Policy (section 10 of the contract): `auto` runs on the agent's say,
183
+ `confirm` asks the person first (under an MCP client, the client's own
184
+ permission prompt is the person's consent), `forbid` is declared but never
185
+ runnable. Every act is written to the audit log with the agent's reason.
186
+
187
+ Cost: detached, every operation above is a load or a store. Keep your own
188
+ handlers cheap too; the agent's model calls never run on the program's
189
+ thread in sidecar mode, and in turns mode they run only inside the
190
+ touchpoints you placed.
191
+
192
+ ## 3. The standard entry (entry)
193
+
194
+ Every abaigram answers `<prog> abai ...`. The stub provides it; the
195
+ program hands it the arguments first thing in `main()`:
196
+
197
+ ```ts
198
+ import { runEntry } from "@abaigram/abai-stub";
199
+ import { app } from "./abai.js";
200
+
201
+ async function main(): Promise<void> {
202
+ const code = await runEntry(app, process.argv.slice(2));
203
+ if (code >= 0) {
204
+ process.exitCode = code; // an abai verb ran and said what it had to say
205
+ return;
206
+ }
207
+ // -1: no abai verb; the program's own argument handling follows, untouched
208
+ }
209
+ ```
210
+
211
+ In a module that already runs at top level, the same two statements stand
212
+ on their own: `const code = await runEntry(app, process.argv.slice(2)); if
213
+ (code >= 0) process.exit(code);`. Prefer `process.exitCode` where you can:
214
+ `process.exit` can cut a large `manifest --json` short on a pipe, and
215
+ `abaikit check` reads the entry through one.
216
+
217
+ Added lines, nothing removed: the program's own argument parsing follows
218
+ untouched, and a plain invocation reaches it exactly as before.
219
+
220
+ The verbs the entry serves:
221
+
222
+ ```
223
+ <prog> abai open a session (needs a configured model)
224
+ <prog> abai install run the install touchpoint
225
+ <prog> abai run -- ARGS sidecar launch: the harness starts "<prog> ARGS" as its child
226
+ <prog> abai config machine-level model and credential settings (~/.abai)
227
+ <prog> abai doctor offline: manifest, entry, content, modes; online: the model
228
+ <prog> abai manifest print the effective manifest
229
+ <prog> abai mcp serve the agent's tools to an MCP client over stdio
230
+ ```
231
+
232
+ The manifest exists twice and must agree: in code (the source of truth at
233
+ runtime) and as `abaigram.yaml` at the repository root, generated by the
234
+ program itself and checked in:
235
+
236
+ ```
237
+ <entry> manifest > abaigram.yaml
238
+ <entry> doctor --offline
239
+ ```
240
+
241
+ The `entry` field is a command line that runs in the repository root; the
242
+ tools reach the program through it. `node dist/main.js abai`, `npx myprog
243
+ abai`, `./bin/myprog abai` are all fine; `myprog abai` only once `myprog`
244
+ is on the PATH.
245
+
246
+ Content lives in `abai/` at the root unless the manifest says otherwise:
247
+ `abai/identity.md` (required: who the agent is for this program and how
248
+ it should behave), `abai/install.md`, `abai/use.md`, `abai/turns/<name>.md`.
249
+ The harness composes the system prompt from `identity`, the mode, and
250
+ every declaration rendered with its `doc`. Good `doc` fields are most of
251
+ the work of good content.
252
+
253
+ ## 4. Conformance levels and what check demands (levels)
254
+
255
+ No level needs a model. `abaikit check <repo>` verifies them with the
256
+ null harness, a harness that attaches and drives nothing (passive) or
257
+ drives every declared knob and capability by its declared default and
258
+ `example` (active, the "exercise run").
259
+
260
+ | Level | Name | Requires |
261
+ |---|---|---|
262
+ | L1 | reachable | The stub is included; `<entry> manifest` works; `abaigram.yaml` exists, validates and agrees with the code; `abai/identity.md` exists; the offline `doctor` passes. Checked without running the program beyond its entry. |
263
+ | L2 | observable | L1, plus `check.run`, plus at least one cell written or event emitted during the exercise run. |
264
+ | L3 | steerable | L2, plus one capability the exercise calls successfully with its `example`, or one knob whose write lands. |
265
+ | L4 | deliberative | L3, plus one decision the program reaches during the exercise run. |
266
+
267
+ L1 is what `<entry> doctor --offline` checks; `abaikit check` repeats it
268
+ from outside and adds the levels above.
269
+
270
+ `check.run` is a command, run by the shell in the repository root, that
271
+ exercises the program's channels and exits: a demo mode, a short batch, a
272
+ dry run. `check` runs it with `ABAI_HARNESS=exercise` (the active null
273
+ harness, which also stands in for the person's consent on `confirm`
274
+ acts) under each declared mode (`ABAI_MODE`), and reads the report the
275
+ stub prints at exit. It then measures: the same command with
276
+ `ABAI_HARNESS=off` (nothing attaches) and `ABAI_HARNESS=null` (the
277
+ passive harness), side by side; a declared `check.overhead` (such as
278
+ `"5%"`) fails the check when the null run is slower than that. Every
279
+ declaration the exercise could not reach is named in the report,
280
+ capabilities without an `example` included. The exercise and measurement
281
+ runs attach the null harness, so the audit log the manifest names
282
+ receives their records: keep that file out of version control, or point
283
+ `audit.path` outside the checkout.
284
+
285
+ ```
286
+ abaikit check <repo> # the level reached, modes, overhead, unexercised, violations
287
+ abaikit check <repo> --level 3 # exit non-zero below level 3
288
+ abaikit check <repo> --json
289
+ ```
290
+
291
+ A program is at the level `check` can demonstrate, not the level you
292
+ intended. If a channel is only reached by a path `check.run` does not
293
+ take, change `check.run`, not the claim.
294
+
295
+ ## 5. The retrofit, step by step (retrofit)
296
+
297
+ Follow the repository's own guidelines and conventions first: its
298
+ `AGENTS.md` or `CONTRIBUTING.md`, its module system (ESM or CommonJS,
299
+ TypeScript or JavaScript), its linter and formatter, its test command.
300
+ Everything you add is additive: new files, inserted lines, two added
301
+ dependencies. You never rewrite `main()`, never delete a line, never
302
+ reorder existing code.
303
+
304
+ Step 0. Know the program. Find the package manifest, the entry file the
305
+ `bin` or `main` points at, how it is built and run, and where its state
306
+ already lives (a queue, a counter, a config). Verify: you can name the
307
+ file where the program's own argument handling starts, and the command
308
+ that runs the program.
309
+
310
+ Step 1. Add the dependencies, in the repository root.
311
+
312
+ ```
313
+ npm install {{abai_spec}} {{harness_spec}}
314
+ ```
315
+ {{workspace_note}}
316
+ Verify, in the repository root:
317
+ `node -e "import('@abaigram/abai-stub').then(m => console.log(m.ABAI_STUB_VERSION))"`
318
+ prints `{{stub}}`.
319
+
320
+ Step 2. Declare the abaigram in a new module (`src/abai.ts`, or
321
+ `src/abai.js` in a JavaScript repository) as in section 2, with only
322
+ `name`, a runnable `entry`, `modes: ["turns", "sidecar"]`, `content` and
323
+ `root` to begin with. When the program's real entry is a plain launcher
324
+ that runs without the build (a `bin/x.mjs` that imports `dist/`), put the
325
+ declaration beside it as a `.mjs` module the launcher can import, so the
326
+ entry answers `manifest` and `doctor` before anything is built. Verify: build as the repository does, then
327
+ `node -e "import('./dist/abai.js')"` (the built path) runs without error.
328
+
329
+ Step 3. Hook the entry. In the file where `main()` starts, insert the
330
+ lines of section 3 before the program's own argument handling. The entry
331
+ runs the built program, so from here on every change is: build (the
332
+ repository's build script), then `<entry> manifest > abaigram.yaml`, then
333
+ verify. Verify: `<entry> manifest` prints YAML, and the program's own
334
+ usage (`<prog> --help`, or whatever it answered before) is unchanged.
335
+
336
+ Step 4. Write `abai/identity.md`: who the agent is for this program, what
337
+ it is for, how it should behave, in a few sentences. Verify:
338
+ `<entry> doctor --offline` prints an `identity` line that begins with `ok`.
339
+
340
+ Step 5. Generate the manifest file and reach L1.
341
+
342
+ ```
343
+ <entry> manifest > abaigram.yaml
344
+ abaikit check .
345
+ ```
346
+
347
+ Verify: the report says level 1. Commit `abaigram.yaml`, `abai/`, the new
348
+ module, the inserted lines, `package.json` and its lock file; nothing else
349
+ changed.
350
+
351
+ Step 6. Observe: L2. Declare one or two cells and events where the program
352
+ already has the facts (a depth, a count, a failure), and set or emit them
353
+ in the existing code paths, one line each. Add `check: { run: "<a short
354
+ command that exercises them>" }` to the declaration, a mode of the
355
+ program that runs for seconds and exits (a `--demo` flag you add, a small
356
+ fixed input, a dry run). Build, regenerate `abaigram.yaml`, verify: `abaikit check .
357
+ --level 2`.
358
+
359
+ Step 7. Steer: L3. Declare one knob the program already reads as a
360
+ setting (with its current value as the `default` and a safe `range`), or
361
+ one capability with a handler and an `example` whose call is harmless.
362
+ Build, regenerate, verify: `abaikit check . --level 3`; the report names
363
+ the knob as landed or the capability as called.
364
+
365
+ Step 8. Deliberate: L4. At a real fork in the program (retry or give up,
366
+ scale or wait), declare a decision with `options`, a `default` that is
367
+ what the program does today, and a short `timeout`; insert `const choice
368
+ = await app.decide("on_retry", { ... })` above the fork and add a branch
369
+ on `choice`, the existing path staying as the branch the default chooses.
370
+ Make sure `check.run` reaches the fork. Build, regenerate, verify:
371
+ `abaikit check . --level 4`.
372
+
373
+ Step 9. Meet the agent. With a model configured (`<entry> config set
374
+ provider ...`, `<entry> config set model ...`, `<entry> config set key
375
+ ...`, then `<entry> doctor`), open `<entry>` and ask what it sees; or run
376
+ `<entry> run -- ARGS` and watch it supervise; or serve `<entry> mcp` to
377
+ Claude Code (section 6). Say what you added and why in the commit
378
+ message and, if the repository keeps one, its changelog.
379
+
380
+ If `abaikit check` reports a violation, read its location and message:
381
+ they name the file or the declaration and what the contract wanted.
382
+
383
+ ## 6. Running an abaigram (use)
384
+
385
+ Session on the terminal, the person talking to the agent while the
386
+ program runs (turns mode in-process; sidecar attaches to or starts the
387
+ harness binary):
388
+
389
+ ```
390
+ <entry>
391
+ ```
392
+
393
+ Launch under supervision, the harness as the parent with the whole
394
+ lifecycle channel (pause, resume, stop, restart, status) and the
395
+ program's output observed from outside:
396
+
397
+ ```
398
+ <entry> run -- ARGS
399
+ abaikit run <repo> -- ARGS # the same, from outside the repository
400
+ ```
401
+
402
+ An MCP client as the agent, no model configured anywhere: the client's
403
+ own agent uses the program's tools, and the client's permission prompt is
404
+ the person's consent.
405
+
406
+ ```json
407
+ { "mcpServers": { "myprog": { "command": "node", "args": ["/abs/path/to/dist/main.js", "abai", "mcp"] } } }
408
+ ```
409
+
410
+ (An absolute path, or run `claude` from the repository root: the client
411
+ starts the command from wherever it is.)
412
+
413
+ ```
414
+ claude -p "what is the program doing?" --mcp-config mcp.json --strict-mcp-config --allowedTools "mcp__myprog__*"
415
+ ```
416
+
417
+ The machine-level model configuration, shared by every abaigram on the
418
+ machine, lives under `~/.abai/`:
419
+
420
+ ```
421
+ <entry> config set provider anthropic|freetoken
422
+ <entry> config set model <id>
423
+ <entry> config set key <provider> # read without echo
424
+ <entry> config set url <provider> <base url>
425
+ <entry> doctor # offline checks, then the model
426
+ ```
427
+
428
+ Environment variables, all optional: `ABAI_MODE` (`turns` or `sidecar`,
429
+ overriding the manifest's first mode), `ABAI_HARNESS` (`off`, `null`,
430
+ `exercise`: check runs only; never set it for real use), `ABAI_HOME` (the
431
+ configuration directory, default `~/.abai`), `ABAI_RUN_DIR` (descriptors
432
+ of running programs, default `~/.abai/run`), `ABAI_HARNESS_BIN` (the
433
+ sidecar harness binary to spawn), `ABAI_HARNESS_MODULE` (the in-process
434
+ harness module to import), `ABAI_CHANNEL` (`terminal` or `none`),
435
+ `ABAI_ATTACH_WAIT_MS` (how long a touchpoint waits for a harness).
436
+
437
+ The audit log (`audit.path` in the manifest; default
438
+ `~/.abai/audit/<name>.jsonl`) records every act of control with its
439
+ reason, consent and outcome. Read it when you wonder what the agent did.
440
+
441
+ ## 7. Where this instantiation departs from the contract (deviations)
442
+
443
+ The first four are in every manifest this stub writes, the last when
444
+ `sidecar` is declared, so an agent reading the manifest sees them too:
445
+
446
+ {{deviations}}
447
+
448
+ ## 8. What never to do (never)
449
+
450
+ - Never rewrite, wrap or replace `main()`. The entry hook is a few
451
+ inserted lines at its top; the program's own flow follows them.
452
+ - Never delete or reorder existing lines. A retrofit is additive; a
453
+ reviewer should see only added lines and new files.
454
+ - Never put the stub behind a condition. The entry must be reachable on
455
+ every invocation, or `check` cannot reach L1.
456
+ - Never leave a capability on the default `safepoint` dispatch in a
457
+ program that never calls `app.safepoint()`: the call stays pending and
458
+ `check` never reaches L3.
459
+ - Never block in a handler or a `set`. Long work belongs behind an
460
+ `immediate`-dispatched async capability, or in a job the handler
461
+ enqueues.
462
+ - Never declare an `example` whose call changes real state. The exercise
463
+ run calls it; so will a curious agent.
464
+ - Never declare a knob without a safe `default` and `range`, a decision
465
+ without the `default` the program chooses today, or a turn without a
466
+ `timeout`.
467
+ - Never put secrets or credentials in content or `doc` fields; they are
468
+ the prompt.
469
+ - Never claim a level `check` did not report, and never change a level by
470
+ editing `abaigram.yaml` by hand: it is generated, and `check` compares
471
+ it with the code.
472
+ - Never make `check.run` depend on the network, credentials, or state it
473
+ does not create itself.
474
+ - Never touch `node_modules`, build output, or files `.gitignore` names.
package/abai/use.md ADDED
@@ -0,0 +1 @@
1
+ A session with abaikit is about one repository at a time. Start by listing it and reading its package manifest and entry file; propose before you write; after every write, run check and read its report.