anchor-ai-sdk 0.0.1 → 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.
package/README.md CHANGED
@@ -1,53 +1,71 @@
1
- # Anchor
2
-
3
- **Loop-first, sandbox-first agent framework.** An agent engine you can
4
- actually inspect: it composes its prompt, calls any OpenAI-compatible model,
5
- executes tools inside an isolated sandbox, journals every event, folds its own
6
- context, and stops honestly — a final response ends the turn, and nothing
7
- pretends a test passed.
8
-
9
- > **0.0.1 — early alpha.** This is a real, working build (engine, tools, LLM
10
- > client, three sandbox adapters, 193 tests), published to claim the name and
11
- > start the version history. The API will move before 1.0 — pin exact
12
- > versions. Repo: [github.com/hrithikkoduri/anchor-ai-sdk](https://github.com/hrithikkoduri/anchor-ai-sdk).
13
- > Docs: [anchor-sdk.dev](https://anchor-sdk.dev) (coming).
14
-
15
- ## What's in the box
16
-
17
- - **The engine** (`runAgent`): budgets, guardrails on by default, compaction
18
- derived from the model's real context window, trace sinks with one sequence
19
- number, revival handoffs, and configurable run snapshots.
20
- - **A tool protocol** — `bash`, `read_file`, `edit_file`, `search`,
21
- `run_tests` — with structured results. Test evidence is tied to the exact
22
- tree it ran against (`run_tests` records the tree hash); "green" only counts
23
- if the tree still matches.
24
- - **A provider-agnostic LLM client**: streaming by default, priced and
25
- windowed from the provider catalog (`llmFromCatalog`).
26
- - **Sandbox providers behind one contract**, accepted by an executable
27
- conformance suite (exec fidelity, kill deadlines, checkpoints,
28
- retain/adopt, git identity, pushes).
29
- - **Durable memory**: `ThreadStore` for conversation, git-backed checkpoints
30
- for the workspace, and a reserved notes file (`.anchor/notes.md`) that
31
- rides checkpoints — the agent's own durable record across folds and
32
- restarts.
33
-
34
- ## Quickstart
1
+ <p align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/hrithikkoduri/anchor-ai-sdk/main/assets/logo-dark.svg" />
4
+ <img src="https://raw.githubusercontent.com/hrithikkoduri/anchor-ai-sdk/main/assets/logo.svg" alt="Anchor" width="96" />
5
+ </picture>
6
+ </p>
7
+
8
+ <h1 align="center">Anchor</h1>
9
+
10
+ <p align="center">
11
+ <strong>Loop-first, sandbox-first agent harness SDK.</strong><br />
12
+ Give it a task and a machine — it reasons, runs tools, checks its own work, and keeps the receipts.
13
+ </p>
14
+
15
+ <p align="center">
16
+ <a href="https://www.npmjs.com/package/anchor-ai-sdk"><img src="https://img.shields.io/npm/v/anchor-ai-sdk?style=flat-square&color=0f1115" alt="npm" /></a>
17
+ <a href="https://github.com/hrithikkoduri/anchor-ai-sdk/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/hrithikkoduri/anchor-ai-sdk/ci.yml?style=flat-square&label=ci&color=0f1115" alt="CI" /></a>
18
+ <a href="LICENSE"><img src="https://img.shields.io/npm/l/anchor-ai-sdk?style=flat-square&color=0f1115" alt="license" /></a>
19
+ <img src="https://img.shields.io/node/v/anchor-ai-sdk?style=flat-square&color=0f1115" alt="node" />
20
+ </p>
21
+
22
+ ---
23
+
24
+ Most agent harnesses give you a loop and leave the hard parts to you: a
25
+ context that grows until it dies, a trace you can't replay, a "done" you can't
26
+ trust. Anchor ships the hard parts.
27
+
28
+ - **Evidence, never vibes.** Every tool result is recorded on
29
+ `AgentResult.evidence`; `run_tests` stamps the tree hash it ran against and
30
+ `latestEvidenceForTree` ties a green run to the *exact* bytes (fail-closed
31
+ when the tree can't be inspected). The engine carries evidence and never
32
+ reads success out of a confident sentence — what to gate on it is your
33
+ policy, not a hidden wall.
34
+ - **Durable by construction.** Conversation, workspace, and the agent's own
35
+ notes survive folds, restarts, and budget deaths; the SDK ships the
36
+ resumption primitives (thread store, checkpoints, phase pauses, revival
37
+ planning), so resuming is wiring, not research.
38
+ - **Sandbox-first.** The machine is part of the design, not an afterthought:
39
+ one provider contract, adapters accepted by an executable conformance
40
+ suite.
41
+
42
+ ## Out of the box
43
+
44
+ | | |
45
+ | --- | --- |
46
+ | **Agent loop with dials** | Budgets (steps / tokens / USD), repeated-call detection, silent-tool advisories — guardrails on by default, each with an off switch. Phases describe the approach — never a second gated execution engine. |
47
+ | **Streaming by default** | One wire path: every model call streams. Text and reasoning deltas, tool calls, compaction, checkpoints, and finishes all arrive as typed events. |
48
+ | **Durable memory** | `ThreadStore` carries conversation across runs; compaction is derived from the model's *real* context window; reasoning is journaled but never re-sent. |
49
+ | **Notes & spill storage** | A reserved `.anchor/notes.md` (git-excluded, checkpoint-carried) is the agent's durable memory across folds; oversized tool output spills to sandbox files and stays addressable instead of vanishing. |
50
+ | **Revival** | A dying run leaves a handoff (`request_revival`); `planRevival` + `ThreadBudget` decide how to fund the next run — **same task, phase, and budget** — and when the thread's caps are spent, a human gets the note, quoting the agent's own words on what remains. |
51
+ | **Snapshots & resume** | A pluggable snapshot hook (git-backed by default, push optional), phase-boundary pauses, heartbeats and cross-process cancel polling owned by the engine. |
52
+ | **Traces you can replay** | One fanout: one sequence number, redaction applied before *every* sink — NDJSON file, database rows, and a live projector share the same ordering. |
53
+ | **Sandbox plugins** | One `SandboxProvider` contract: Heyo microVMs, Docker, local. Capabilities are promises — the conformance suite holds adapters to them. Store-backed sessions give adopt-and-fallback continuity for free. |
54
+ | **Typed handoffs** | `finish({ handoff })` is shaped by *your* JSON schema; the engine declares the parameter, carries the object, and never interprets it. |
55
+ | **Priced & windowed models** | `llmFromCatalog` reads live prices and the genuine context window from the provider catalog — budgets and compaction configure themselves correctly. |
56
+
57
+ ## Ten lines to a working agent
35
58
 
36
59
  ```bash
37
60
  npm install anchor-ai-sdk
38
61
  ```
39
62
 
40
63
  ```ts
41
- import {
42
- chatAgent,
43
- createLLMClient,
44
- llmFromCatalog,
45
- runAgent,
46
- } from "anchor-ai-sdk";
64
+ import { chatAgent, llmFromCatalog, runAgent } from "anchor-ai-sdk";
47
65
 
48
66
  const { llm } = await llmFromCatalog({
49
67
  baseUrl: "https://openrouter.ai/api/v1",
50
- apiKey: process.env.OPENROUTER_KEY,
68
+ apiKey: process.env.OPENROUTER_KEY!,
51
69
  model: "z-ai/glm-5.3",
52
70
  });
53
71
 
@@ -58,14 +76,13 @@ const result = await runAgent(
58
76
  console.log(result.summary);
59
77
  ```
60
78
 
61
- With a sandbox — Docker shown; the `local` backend needs no daemon:
79
+ ## Give it a machine
62
80
 
63
81
  ```ts
64
- import { codingAgent, createLLMClient, runAgent } from "anchor-ai-sdk";
82
+ import { codingAgent, runAgent } from "anchor-ai-sdk";
65
83
  import { docker } from "anchor-ai-sdk/sandbox/docker";
66
84
 
67
- const provider = docker();
68
- const sandbox = provider.create({
85
+ const sandbox = docker().create({
69
86
  repoUrl: "https://github.com/you/your-repo",
70
87
  ref: "main",
71
88
  });
@@ -73,15 +90,9 @@ await sandbox.start();
73
90
  try {
74
91
  const result = await runAgent(
75
92
  { task: "Run the tests and fix the failing case" },
76
- {
77
- llm: createLLMClient({
78
- /* … */
79
- }),
80
- agent: codingAgent,
81
- sandbox,
82
- },
93
+ { llm, agent: codingAgent, sandbox },
83
94
  );
84
- console.log(result.summary);
95
+ console.log(result.summary, result.checkpointRef);
85
96
  } finally {
86
97
  await sandbox.destroy();
87
98
  }
@@ -89,28 +100,38 @@ try {
89
100
 
90
101
  ## Providers
91
102
 
92
- | subpath | backend | status |
93
- | ------------------------------ | --------------------------------- | ----------------------------------------- |
94
- | `anchor-ai-sdk/sandbox/heyo` | Heyo Cloud microVMs (Firecracker) | production path; conformance + live tests |
95
- | `anchor-ai-sdk/sandbox/docker` | containers on the local daemon | conformance-tested |
96
- | `anchor-ai-sdk/sandbox/local` | this host, **no isolation** | dev / CI only |
97
- | — | E2B, Daytona | planned — not exported yet |
103
+ | subpath | backend | status |
104
+ | --- | --- | --- |
105
+ | `anchor-ai-sdk/sandbox/heyo` | Heyo Cloud microVMs (Firecracker) | production path; conformance + live tests |
106
+ | `anchor-ai-sdk/sandbox/docker` | containers on the local daemon | conformance-tested in CI |
107
+ | `anchor-ai-sdk/sandbox/local` | this host, **no isolation** | dev / CI only |
108
+ | — | E2B, Daytona | planned |
98
109
 
99
110
  A backend is "done" when `runSandboxConformance(provider)` from
100
- `anchor-ai-sdk/testing` passes. The suite gates scenarios on declared
101
- capabilities; capabilities are promises, not vibes.
102
-
103
- ## The philosophy, short
104
-
105
- Trust the reasoning; verify the claims. The engine carries _evidence_ instead
106
- of asserting success: a passing test run is a structured event tied to the
107
- exact tree; publication is an explicit tool call gated on that evidence; a
108
- worker death resumes from a checkpoint instead of re-deriving or pretending.
109
- The same discipline is being measured: Anchor vs mini-swe-agent on SWE-bench
110
- Lite, same container, same model, same grader — equal resolution at roughly
111
- one-third the cost. The comparison table ships with the first tagged release.
112
-
113
- ## Status & links
111
+ `anchor-ai-sdk/testing` passes — exec fidelity, kill deadlines, env secrets,
112
+ checkpoints, retain/adopt, git identity, pushes, and `fork` where declared.
113
+ See [`src/sandbox/README.md`](src/sandbox/README.md) for the provider guide.
114
+
115
+ ## Proof, not promises
116
+
117
+ - **Tests:** the engine, tools, trace layer, and every provider scenario run
118
+ in CI — local conformance always, Docker conformance on a purpose-built
119
+ image. Live microVM conformance is opt-in with your own Heyo credentials
120
+ (the suite skips without them).
121
+ - **Genericity guards:** executable rules keep the package consumer-neutral —
122
+ no product nouns, no env reads, SDKs behind subpaths. They run in the same
123
+ suite as everything else.
124
+ - **Evaluation:** Anchor vs mini-swe-agent on SWE-bench Lite — same
125
+ container, same model, same official grader — resolved the same 7/10 at
126
+ roughly **one-third of the cost**
127
+ ([`evals/results/comparison.md`](evals/results/comparison.md)).
128
+
129
+ ## Status
130
+
131
+ **Early alpha (0.x).** The API will move before 1.0 — pin exact versions. The
132
+ [`DECISIONS.md`](DECISIONS.md) is the engineering log: every API has a written
133
+ reason, and the reasons moved with the code when this repo was extracted from
134
+ its monorepo.
114
135
 
115
136
  - Repo / issues: [github.com/hrithikkoduri/anchor-ai-sdk](https://github.com/hrithikkoduri/anchor-ai-sdk)
116
137
  - Docs: [anchor-sdk.dev](https://anchor-sdk.dev) (coming)
@@ -7,7 +7,7 @@ export { codingPhases } from "./phases.js";
7
7
  /**
8
8
  * The coding agent — strategy + toolbox. Pass `testCommand` when the repo's
9
9
  * canonical suite is known (CLI or repo config); otherwise run_tests detects
10
- * one and the evidence gates still apply.
10
+ * one; either way run_tests tags the run as the repo's full-suite evidence.
11
11
  */
12
12
  export declare function createCodingAgent(opts?: {
13
13
  testCommand?: string;
@@ -7,7 +7,7 @@ export { codingPhases } from "./phases.js";
7
7
  /**
8
8
  * The coding agent — strategy + toolbox. Pass `testCommand` when the repo's
9
9
  * canonical suite is known (CLI or repo config); otherwise run_tests detects
10
- * one and the evidence gates still apply.
10
+ * one; either way run_tests tags the run as the repo's full-suite evidence.
11
11
  */
12
12
  export function createCodingAgent(opts = {}) {
13
13
  return {
@@ -12,8 +12,7 @@ import type { Tool } from "../../tools/types.js";
12
12
  /**
13
13
  * The toolbox for one coding agent. `testCommand` — when the repo's canonical
14
14
  * suite is known from config/CLI — becomes run_tests' fallback and counts as
15
- * full-suite evidence (the strategy's evidence gates care about that
16
- * distinction).
15
+ * full-suite evidence (publication policies gate on that distinction).
17
16
  */
18
17
  export declare function createCodingTools(opts?: {
19
18
  testCommand?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/agents/coding/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAOjD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,IAAI,EAAE,CAQ7E;AAED,wEAAwE;AACxE,eAAO,MAAM,WAAW,EAAE,IAAI,EAAwB,CAAC"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/agents/coding/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAOjD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,IAAI,EAAE,CAQ7E;AAED,wEAAwE;AACxE,eAAO,MAAM,WAAW,EAAE,IAAI,EAAwB,CAAC"}
@@ -6,8 +6,7 @@ import { searchTool } from "../../tools/search.js";
6
6
  /**
7
7
  * The toolbox for one coding agent. `testCommand` — when the repo's canonical
8
8
  * suite is known from config/CLI — becomes run_tests' fallback and counts as
9
- * full-suite evidence (the strategy's evidence gates care about that
10
- * distinction).
9
+ * full-suite evidence (publication policies gate on that distinction).
11
10
  */
12
11
  export function createCodingTools(opts = {}) {
13
12
  return [
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/agents/coding/tools.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAI,GAA6B,EAAE;IACnE,OAAO;QACL,QAAQ;QACR,YAAY;QACZ,YAAY;QACZ,UAAU;QACV,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC3E,CAAC;AACJ,CAAC;AAED,wEAAwE;AACxE,MAAM,CAAC,MAAM,WAAW,GAAW,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/agents/coding/tools.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAI,GAA6B,EAAE;IACnE,OAAO;QACL,QAAQ;QACR,YAAY;QACZ,YAAY;QACZ,UAAU;QACV,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC3E,CAAC;AACJ,CAAC;AAED,wEAAwE;AACxE,MAAM,CAAC,MAAM,WAAW,GAAW,iBAAiB,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "anchor-ai-sdk",
3
- "version": "0.0.1",
4
- "description": "Loop-first, sandbox-first agent framework: engine, tools, LLM client, sandbox adapters.",
3
+ "version": "0.1.0",
4
+ "description": "Loop-first, sandbox-first agent harness SDK: engine, tools, LLM client, sandbox adapters.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -52,7 +52,8 @@
52
52
  "prepack": "npm run build",
53
53
  "prepublishOnly": "npm run build && node scripts/verify-dist-exports.mjs",
54
54
  "test": "vitest run",
55
- "typecheck": "tsc --noEmit"
55
+ "typecheck": "tsc --noEmit",
56
+ "prepare": "npm run build"
56
57
  },
57
58
  "peerDependencies": {
58
59
  "@heyocomputer/hws": ">=0.4",