martin-loop 0.1.1 → 0.1.3

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 (62) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +331 -58
  3. package/dist/bin/martin-loop.js +12 -8
  4. package/dist/index.d.ts +21 -8
  5. package/dist/index.js +31 -9
  6. package/dist/vendor/adapters/claude-cli.d.ts +89 -0
  7. package/dist/vendor/adapters/claude-cli.js +555 -0
  8. package/dist/vendor/adapters/cli-bridge.d.ts +28 -0
  9. package/dist/vendor/adapters/cli-bridge.js +127 -0
  10. package/dist/vendor/adapters/direct-provider.d.ts +10 -0
  11. package/dist/vendor/adapters/direct-provider.js +41 -0
  12. package/dist/vendor/adapters/index.d.ts +5 -0
  13. package/dist/vendor/adapters/index.js +5 -0
  14. package/dist/vendor/adapters/runtime-support.d.ts +14 -0
  15. package/dist/vendor/adapters/runtime-support.js +52 -0
  16. package/dist/vendor/adapters/stub-agent-cli.d.ts +8 -0
  17. package/dist/vendor/adapters/stub-agent-cli.js +41 -0
  18. package/dist/vendor/adapters/stub-direct-provider.d.ts +8 -0
  19. package/dist/vendor/adapters/stub-direct-provider.js +10 -0
  20. package/dist/vendor/cli/bin/martin.js +19 -0
  21. package/dist/vendor/cli/index.d.ts +39 -0
  22. package/dist/vendor/cli/index.js +634 -0
  23. package/dist/vendor/cli/persistence.d.ts +34 -0
  24. package/dist/vendor/cli/persistence.js +71 -0
  25. package/dist/vendor/contracts/governance.d.ts +21 -0
  26. package/dist/vendor/contracts/governance.js +12 -0
  27. package/dist/vendor/contracts/index.d.ts +330 -0
  28. package/dist/vendor/contracts/index.js +203 -0
  29. package/dist/vendor/core/compiler.d.ts +50 -0
  30. package/dist/vendor/core/compiler.js +47 -0
  31. package/dist/vendor/core/grounding.d.ts +37 -0
  32. package/dist/vendor/core/grounding.js +270 -0
  33. package/dist/vendor/core/index.d.ts +145 -0
  34. package/dist/vendor/core/index.js +1099 -0
  35. package/dist/vendor/core/leash.d.ts +48 -0
  36. package/dist/vendor/core/leash.js +408 -0
  37. package/dist/vendor/core/persistence/compiler.d.ts +18 -0
  38. package/dist/vendor/core/persistence/compiler.js +35 -0
  39. package/dist/vendor/core/persistence/index.d.ts +6 -0
  40. package/dist/vendor/core/persistence/index.js +4 -0
  41. package/dist/vendor/core/persistence/ledger.d.ts +23 -0
  42. package/dist/vendor/core/persistence/ledger.js +10 -0
  43. package/dist/vendor/core/persistence/store.d.ts +77 -0
  44. package/dist/vendor/core/persistence/store.js +84 -0
  45. package/dist/vendor/core/policy.d.ts +126 -0
  46. package/dist/vendor/core/policy.js +625 -0
  47. package/dist/vendor/core/rollback.d.ts +11 -0
  48. package/dist/vendor/core/rollback.js +219 -0
  49. package/docs/oss/EXAMPLES.md +126 -0
  50. package/docs/oss/OSS-BOUNDARY-REPORT.json +113 -0
  51. package/docs/oss/OSS-BOUNDARY-REPORT.md +48 -0
  52. package/docs/oss/QUICKSTART.md +135 -0
  53. package/docs/{README.md → oss/README.md} +17 -13
  54. package/docs/oss/RELEASE-SURFACE-REPORT.json +45 -0
  55. package/docs/oss/RELEASE-SURFACE-REPORT.md +35 -0
  56. package/package.json +27 -35
  57. package/dist/bin/martin-loop.js.map +0 -1
  58. package/dist/index.js.map +0 -1
  59. package/docs/EXAMPLES.md +0 -96
  60. package/docs/QUICKSTART.md +0 -127
  61. package/docs/release/CLAIM-TO-CAPABILITY.md +0 -19
  62. /package/dist/{bin/martin-loop.d.ts → vendor/cli/bin/martin.d.ts} +0 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MartinLoop contributors
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,89 +1,362 @@
1
- # Martin Loop
1
+ <div align="center">
2
2
 
3
- Governed AI coding runtime with hard budget controls, grounding enforcement, rollback, and a persistent audit trail.
3
+ <img src="./docs/assets/martinloop-logo.png" alt="MartinLoop" width="260">
4
4
 
5
- ## What is validated in this repo
5
+ ### A governed runtime for autonomous AI coding agents. ⭐⭐⭐
6
6
 
7
- - `@martin/core`: runtime controller, policy engine, grounding, leash, rollback
8
- - `@martin/contracts`: shared types for loop, failure, budget, and grounding
9
- - `@martin/adapters`: Claude CLI, Codex CLI, and direct-provider adapters
10
- - `@martin/cli`: repo-local `martin` CLI
11
- - `@martin/mcp`: MCP server surface
12
- - `@martin/sdk`: governance, handoff, and migration primitives
7
+ [![License: MIT](https://img.shields.io/badge/license-MIT-7c3aed?style=flat-square)](./LICENSE)
8
+ [![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6?style=flat-square&logo=typescript&logoColor=white)](./tsconfig.base.json)
9
+ [![Node](https://img.shields.io/badge/node-%3E%3D20-3c873a?style=flat-square&logo=nodedotjs&logoColor=white)](#quick-start)
10
+ [![npm](https://img.shields.io/badge/npm-martin--loop-cc3534?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/martin-loop)
13
11
 
14
- The workspace packages are validated in this snapshot. Public `martin-loop` packaging remains later release work and should not be treated as the verified install path yet.
12
+ <br>
15
13
 
16
- ## Repo-local install
14
+ **Your overnight AI pipeline estimated $2.40.**
15
+ **You woke up to a $65 bill.**
16
+ <br> 47 retries. No hard stop. No rollback. No audit trail. Nothing merged.
17
+ MartinLoop exists so that never happens again.✅ <br> <br>
18
+ If you think autonomous AI coding agents need budgets, brakes, and receipts, ⭐ the repo so more builders can find it.
19
+ <br>
17
20
 
18
- ```bash
19
- git clone https://github.com/Keesan12/MartinLoop
20
- cd martin-loop
21
- pnpm install
22
- pnpm build
21
+ > AI coding agents are useful. Unbounded retry loops are not.
22
+ >
23
+ > MartinLoop wraps agent runs with budgets, policy checks, verifier gates, rollback evidence, and inspectable run records.
24
+ <br>
25
+ <img src="./docs/assets/cli-animated.svg" alt="MartinLoop CLI — governed agent run" width="720">
26
+
27
+ </div>
28
+
29
+ ---
30
+
31
+ ## The Problem
32
+
33
+ A typical autonomous coding loop keeps attempting work until tests pass. Without a governance layer, that loop can keep spending, mutate files outside the intended scope, lose track of why it failed, and leave teams without a clean audit trail.
34
+
35
+ Ralph-style loops are powerful but they attempt ➡️ check ➡️ retry ➡️ repeat, with no strong answer to:
36
+
37
+ - What changed?
38
+ - What did it cost?
39
+ - Why was it allowed?
40
+ - Why did it stop?
41
+ - Can we inspect or resume it later?
42
+
43
+ MartinLoop governs the failure mode.
44
+
45
+ ---
46
+
47
+ ## The Solution
48
+
49
+ ✅ Martin Loop wraps AI coding loops with a governance layer.
50
+
51
+ It does not try to replace the agent pattern. It makes that pattern safe to run.
52
+
53
+ ### What MartinLoop Does Today
54
+
55
+ | Capability | Current behavior |
56
+ |---|---|
57
+ | Budget governance | Enforces `maxUsd`, `softLimitUsd`, `maxIterations`, and `maxTokens`; rejects attempts projected to exceed remaining budget and exits on budget or iteration exhaustion. Hard USD budget caps that stop work before the next attempt breaches policy. |
58
+ | Verifier gate | A run only reaches `completed` when the adapter result and verifier state pass. Unsafe verifier commands are blocked before agent execution. |
59
+ | Failure taxonomy | Classifies failures across 11 current classes, including hallucination, test regression, scope creep, repo grounding failure, environment mismatch, and budget pressure, that distinguishes real success from unsafe, invalid, or terminal behavior.|
60
+ | Safety leash | Evaluates verifier commands, file scope, dependency or migration changes that require approval, and secret-like values in task text. **Policy-as-code**. |
61
+ | Rollback evidence | Captures rollback boundaries and restore outcomes for repo-backed attempts when a persistence store is configured. |
62
+ | Context distillation | Carries a distilled summary of recent attempts and remaining constraints into subsequent attempts. |
63
+ | Run records | The CLI appends JSONL loop records under `~/.martin/runs/<workspaceId>.jsonl`; lower-level stores can also persist contracts, ledgers, and attempt artifacts.
64
+
65
+
66
+ ⭐The result is a runtime that can complete good work, refuse unsafe work, stop uneconomical work, and leave evidence behind.✅
67
+ ---
68
+
69
+ ## The Ralph Loop, explained
70
+
71
+ **"Everybody has gotten infatuated with what we call these Ralph Wiggum loops, just like send the thing off and it'll just go figure something out..A, It never figures anything out. And B, you just get this ginormous bill...**" - Chamath Palihapitiya, All-In Podcast #263, March 2026
72
+
73
+ ⛔ The **Ralph Loop** is the failure mode where an AI coding agent keeps trying without knowing when it should stop.
74
+
75
+ The pattern is simple: attempt the task, run checks, retry on failure, repeat. The problem is not that the loop exists. The problem is that most implementations have no hard budget cap, no signed evidence layer, and no pre-execution control system. They know how to keep trying. They do **not** know when continuing is unsafe, uneconomical, or impossible.
76
+
77
+ ✅ Martin Loop solves the Ralph Loop problem by enforcing rules **before** damage happens:
78
+
79
+ - it stops the next attempt before budget overspend
80
+ - it classifies unsafe or invalid actions before execution
81
+ - it appends a structured JSONL audit record for every attempt
82
+ - it rolls back failed runs instead of leaving broken state behind
83
+ - it reduces runaway token growth with context distillation
84
+
85
+ If Ralph ever burned $165.70 on your dime, you're in the right place. Martin stopped him at $4.97 with a full audit trail. LFG! 🚀 Finally a Martin Prince leash for Ralph Wiggums! :)
86
+
87
+ <div align="center">
88
+ <img src="./docs/assets/martin-raplph.png.jpg" alt="Martin vs Ralph — governed vs ungoverned agent loop" width="240">
89
+ </div>
90
+
91
+ ### How It Works — Five Layers
92
+
93
+ | Layer | What it does |
94
+ |---|---|
95
+ | **1. Task Contract** | Objective, verifier plan, repo root, allowed/denied paths, acceptance criteria, workspace, project, and budget. |
96
+ | **2. Policy & Budget** | Defaults from `martin.config.yaml`; CLI flags override. Budget preflight rejects attempts before execution. |
97
+ | **3. Agent Adapters** | Claude CLI, Codex CLI, direct-provider, and stub adapters normalize execution results into the core runtime contract. |
98
+ | **4. Safety & Verification** | Verifier commands, file scope, approval-boundary changes, secret-like values, and grounding determine whether work is kept. |
99
+ | **5. Persistence** | CLI writes JSONL records under `~/.martin/runs/`. Repo-backed runs can also persist contracts, ledgers, diffs, and rollback artifacts. |
100
+
101
+ ---
102
+
103
+ ## See It In Action
104
+
105
+ Same task, same starting state. MartinLoop completes in one verified attempt at `$2.30`. The uncontrolled loop retries four times, spends `$5.20`, and fails with no audit trail.
106
+
107
+ Martin Loop matters because it turns AI coding from an opaque experiment into something that can be governed, replayed, verified, and trusted.
108
+
109
+ <div align="center">
110
+ <img src="./docs/assets/side-by-side.svg" alt="Martin vs Ralph — governed vs ungoverned agent loop side-by-side benchmark comparison" width="720" height="1080">
111
+ </div>
112
+
113
+
114
+ Reproducible locally:
115
+
116
+ ```sh
117
+ pnpm --filter @martin/benchmarks test
118
+ pnpm --filter @martin/benchmarks eval
119
+ pnpm --filter @martin/benchmarks eval:phase12
23
120
  ```
24
121
 
25
- ## Quick start
122
+ ---
123
+
124
+ ## Quick Start
125
+
126
+ ```sh
127
+ npm install -g martin-loop
128
+ ```
26
129
 
27
- ```bash
28
- pnpm --filter @martin/cli exec martin run \
29
- --objective "Repair the flaky auth test" \
130
+ This installs both the `martin-loop` package and the `martin` command alias. The package is currently published on npm as version `0.1.2`.
131
+
132
+ ### Public Package Surface
133
+
134
+ The frozen public package surface for this release candidate is:
135
+
136
+ - Install target: `npm install martin-loop`
137
+ - CLI target: `npx martin-loop`
138
+ - SDK target: `import { MartinLoop } from "martin-loop"`
139
+
140
+ The `martin` command alias is installed for local operator convenience, but the public CLI surface is `npx martin-loop`.
141
+
142
+ ### Run a governed task
143
+
144
+ ```sh
145
+ martin run "fix the auth regression" \
146
+ --budget 3.00 \
30
147
  --verify "pnpm test"
31
148
  ```
32
149
 
33
- ```bash
34
- pnpm --filter @martin/cli exec martin inspect --file ~/.martin/runs/latest/loop-record.json
150
+ You can also pass the objective explicitly:
151
+
152
+ ```sh
153
+ martin run --objective "fix the auth regression" --budget 3.00 --verify "pnpm test"
154
+ ```
155
+
156
+ For a no-spend repo-local dry run, use the stub adapter:
157
+
158
+ ```powershell
159
+ $env:MARTIN_LIVE='false'
160
+ pnpm run:cli -- run --objective "Summarize the current runtime state" --verify "pnpm --filter @martin/core test"
161
+ Remove-Item Env:MARTIN_LIVE
35
162
  ```
36
163
 
37
- See [docs/QUICKSTART.md](docs/QUICKSTART.md) for the fuller walkthrough and [docs/EXAMPLES.md](docs/EXAMPLES.md) for more runnable examples.
164
+ ### Inspect or resume runs
165
+
166
+ ```sh
167
+ martin inspect --file ~/.martin/runs/<workspaceId>.jsonl
168
+ martin resume <loopId>
169
+ ```
38
170
 
39
- ## Programmatic usage
171
+ `inspect` prints a portfolio summary for records in the file. `resume` looks up a persisted loop record by ID under `~/.martin/runs/`.
40
172
 
41
- ```ts
42
- import { runMartin } from "@martin/core";
173
+ ---
43
174
 
44
- const result = await runMartin({
45
- workspaceId: "ws_local",
46
- projectId: "proj_auth",
175
+ ## CLI
176
+
177
+ ```text
178
+ martin run <objective> [options]
179
+
180
+ --objective <text> The task to accomplish, or pass it as the first positional arg
181
+ --budget <n> Hard cost cap in USD
182
+ --budget-usd <n> Alias for --budget
183
+ --soft-limit-usd <n> Soft budget threshold in USD
184
+ --verify <cmd> Verifier command after each attempt
185
+ --max-iterations <n> Maximum number of attempts
186
+ --max-tokens <n> Maximum total token budget
187
+ --engine <name> Adapter to use: claude (default) or codex
188
+ --model <name> Override the adapter model
189
+ --cwd <path> Repo root for the run
190
+ --allow-path <glob> Restrict agent writes to this path pattern; repeatable
191
+ --deny-path <glob> Block this path pattern; repeatable
192
+ --accept <criterion> Add an acceptance criterion; repeatable
193
+ --config <path> Path to a martin.config.yaml file
194
+ --workspace <id> Workspace ID for the run record
195
+ --project <id> Project ID for the run record
196
+ --metadata <key=value> Attach metadata to the run record; repeatable
197
+ ```
198
+
199
+ The public CLI also includes `inspect`, `resume`, and a `bench` redirect that points reviewers to the workspace benchmark harness.
200
+
201
+ <div align="center">
202
+ <img src="./docs/assets/cli-static.svg" alt="MartinLoop CLI terminal output" width="720">
203
+ </div>
204
+
205
+ ---
206
+
207
+ ## Policy File
208
+
209
+ Drop a `martin.config.yaml` in your repo root to set governance defaults:
210
+
211
+ ```yaml
212
+ budget:
213
+ maxUsd: 5.00
214
+ softLimitUsd: 3.75
215
+ maxIterations: 5
216
+ maxTokens: 40000
217
+
218
+ governance:
219
+ destructiveActionPolicy: approval
220
+ telemetryDestination: local-only
221
+ verifierRules:
222
+ - pnpm test
223
+ ```
224
+
225
+ CLI flags override config values when provided.
226
+
227
+ ---
228
+
229
+ ## TypeScript SDK
230
+
231
+ ```sh
232
+ npm install martin-loop
233
+ ```
234
+
235
+ ```typescript
236
+ import {
237
+ MartinLoop,
238
+ createClaudeCliAdapter,
239
+ createCodexCliAdapter,
240
+ runMartin
241
+ } from "martin-loop";
242
+
243
+ const loop = new MartinLoop({
244
+ adapter: createClaudeCliAdapter({ workingDirectory: process.cwd() }),
245
+ defaults: {
246
+ workspaceId: "my-workspace",
247
+ projectId: "my-project",
248
+ budget: {
249
+ maxUsd: 3.00,
250
+ softLimitUsd: 2.25,
251
+ maxIterations: 3,
252
+ maxTokens: 20_000
253
+ }
254
+ }
255
+ });
256
+
257
+ const result = await loop.run({
47
258
  task: {
48
- title: "Repair the flaky auth test",
49
- objective: "Repair the flaky auth test without widening scope.",
50
- verificationPlan: ["pnpm test"]
51
- },
52
- budget: {
53
- maxUsd: 0.5,
54
- softLimitUsd: 0.3,
55
- maxIterations: 4,
56
- maxTokens: 20_000
57
- },
58
- adapter
259
+ title: "Fix auth regression",
260
+ objective: "Fix the failing auth regression tests",
261
+ verificationPlan: ["pnpm test"],
262
+ repoRoot: process.cwd()
263
+ }
59
264
  });
60
265
 
61
- console.log(result.decision.lifecycleState);
266
+ console.log(result.decision.status);
267
+ ```
268
+
269
+ Use Codex instead of Claude by swapping adapters:
270
+
271
+ ```typescript
272
+ const loop = new MartinLoop({
273
+ adapter: createCodexCliAdapter({ workingDirectory: process.cwd() })
274
+ });
62
275
  ```
63
276
 
64
- ## Validation
277
+ The lower-level `runMartin` function is also exported for callers that want to assemble the runtime input directly.
278
+
279
+ ---
280
+
281
+ ## Workspace Map
282
+
283
+ | Package or app | Role |
284
+ |---|---|
285
+ | `martin-loop` | Root public npm facade that vendors the runtime, CLI, adapters, and contracts into `dist/`. |
286
+ | `@martin/contracts` | Shared types for loops, policy, governance, budget, telemetry, and rollback. |
287
+ | `@martin/core` | Runtime controller, policy engine, safety leash, grounding, persistence, and rollback logic. |
288
+ | `@martin/adapters` | Claude CLI, Codex CLI, direct-provider, and stub adapter surfaces. |
289
+ | `@martin/cli` | Local CLI implementation for `run`, `inspect`, `resume`, and the benchmark redirect. |
290
+ | `@martin/mcp` | MCP server tools: `martin_run`, `martin_inspect`, and `martin_status`. |
291
+ | `benchmarks/` | Workspace-only deterministic benchmark and RC validation harness. |
292
+ | `apps/control-plane/` | Hosted control-plane workstream, outside the initial npm package surface. |
293
+ | `apps/local-dashboard/` | Local dashboard/read-model viewer, not currently packaged as public npm API. |
294
+
295
+ The `@martin/core`, `@martin/adapters`, and `@martin/contracts` package manifests are still private workspace packages; the public install target is the root `martin-loop` facade.
296
+
297
+ ---
298
+
299
+ ## Development
300
+
301
+ Requirements: Node 20+ and pnpm 10.x.
302
+
303
+ ```sh
304
+ git clone https://github.com/Keesan12/martin-loop.git
305
+ cd martin-loop
306
+ pnpm install
65
307
 
66
- ```bash
67
308
  pnpm test
309
+ pnpm lint
68
310
  pnpm build
69
- pnpm typecheck
70
311
  ```
71
312
 
72
- ## Artifacts
313
+ ```md
314
+ Current RC gate commands:
73
315
 
74
- ```text
75
- ~/.martin/runs/<run-id>/
76
- contract.json
77
- state.json
78
- ledger.jsonl
79
- artifacts/attempt-001/
80
- diff.patch
81
- grounding-scan.json
82
- leash.json
83
- patch-decision.json
84
- rollback-outcome.json
316
+ ```sh
317
+ pnpm oss:validate
318
+ pnpm public:smoke
319
+ pnpm repo:smoke
320
+ pnpm rc:validate
321
+ pnpm pilot:prep:validate
322
+ pnpm release:matrix:local
323
+ Caution: Registry Publication
324
+
325
+ This package is published through the public martin-loop package surface. Treat registry publication as a guarded release step: verify the RC gate commands, confirm the version follows semantic versioning, and document breaking changes before publishing.
326
+
327
+ > **Caution:** This package is live on npm. Treat registry publication as a guarded release step — verify the RC gate commands, confirm semantic versioning, and document breaking changes before publishing.
328
+
329
+ The repository is organized as a dual-track workspace: the OSS runtime and package facade are present and published, while the hosted control-plane, local dashboard, and benchmark harness remain gated in private workspace for future release rather than the primary npm package API.
330
+
331
+ Helpful docs:
332
+
333
+ - [OSS quickstart](./docs/oss/QUICKSTART.md)
334
+ - [OSS examples](./docs/oss/EXAMPLES.md)
335
+ - [OSS boundary report](./docs/oss/OSS-BOUNDARY-REPORT.md)
336
+ - [Release surface report](./docs/oss/RELEASE-SURFACE-REPORT.md)
337
+
338
+ ---
339
+
340
+ ## Contributing
341
+
342
+ ```sh
343
+ git checkout -b feat/your-feature
344
+ pnpm lint
345
+ pnpm test
346
+ git commit -m "feat: describe what you built"
347
+ git push -u origin feat/your-feature
85
348
  ```
86
349
 
87
- ## License
350
+ Conventional commit prefixes: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`, and `test:`.
351
+
352
+ ---
353
+
354
+ <div align="center">
355
+
356
+ **⭐Give the repo a star⭐** if you think AI coding needs budgets, brakes, and receipts.
357
+
358
+ **MIT Licensed** · [martinloop.com](https://martinloop.com) · [keesan@martinloop.com](mailto:keesan@martinloop.com)
359
+
360
+ *"AI coding accountability: completes good work, refuses unsafe work, stops uneconomical work."*
88
361
 
89
- MIT. See [LICENSE](LICENSE).
362
+ </div>
@@ -1,19 +1,23 @@
1
1
  #!/usr/bin/env node
2
- import { executeCli } from "@martin/cli";
2
+
3
+ import { executeCli } from "../vendor/cli/index.js";
4
+
3
5
  const args = process.argv.slice(2);
6
+
4
7
  executeCli(args)
5
- .then((result) => {
8
+ .then((result) => {
6
9
  if (result.stdout) {
7
- process.stdout.write(`${result.stdout}\n`);
10
+ process.stdout.write(`${result.stdout}\n`);
8
11
  }
12
+
9
13
  if (result.stderr) {
10
- process.stderr.write(`${result.stderr}\n`);
14
+ process.stderr.write(`${result.stderr}\n`);
11
15
  }
16
+
12
17
  process.exitCode = result.exitCode;
13
- })
14
- .catch((error) => {
18
+ })
19
+ .catch((error) => {
15
20
  const message = error instanceof Error ? error.message : String(error);
16
21
  process.stderr.write(`${message}\n`);
17
22
  process.exitCode = 1;
18
- });
19
- //# sourceMappingURL=martin-loop.js.map
23
+ });
package/dist/index.d.ts CHANGED
@@ -1,9 +1,22 @@
1
- import { runMartin } from "@martin/core";
2
- export * from "@martin/core";
3
- export * from "@martin/adapters";
4
- export * from "@martin/sdk";
5
- export { executeCli, parseCliArguments, renderCliHelp } from "@martin/cli";
6
- export declare const MartinLoop: {
7
- run: typeof runMartin;
1
+ export { runMartin, compilePromptPacket, createFileRunStore, makeLedgerEvent, resolveRunsRoot } from "./vendor/core/index.js";
2
+ export type { CompileResult, MartinAdapter, MartinAdapterRequest, MartinAdapterResult, PromptPacket, RunMartinInput, RunMartinResult, RunStore } from "./vendor/core/index.js";
3
+ export { executeCli, parseCliArguments, renderCliHelp } from "./vendor/cli/index.js";
4
+ export type { ParsedCliArguments, RunCommandRequest } from "./vendor/cli/index.js";
5
+ export { createClaudeCliAdapter, createCodexCliAdapter, createDirectProviderAdapter, createStubDirectProviderAdapter, createStubAgentCliAdapter } from "./vendor/adapters/index.js";
6
+ export type { AgentCliAdapterOptions, ClaudeCliAdapterOptions, CliArgsBuilder, CodexCliAdapterOptions, DirectProviderAdapterOptions, SpawnLike, StubAgentCliAdapterOptions, StubDirectProviderAdapterOptions, SubprocessResult, VerificationOutcome } from "./vendor/adapters/index.js";
7
+ export { appendLoopEvent, buildPortfolioSnapshot, createGovernanceSnapshot, createLoopRecord, createTelemetryEnvelope, DEFAULT_BUDGET, EMPTY_COST, validateTelemetryBatch, validateTelemetryEnvelope } from "./vendor/contracts/index.js";
8
+ export type { ApprovalPolicy, ExecutionProfile, LoopBudget, LoopRecord, LoopTask } from "./vendor/contracts/index.js";
9
+
10
+ export interface MartinLoopOptions {
11
+ adapter?: MartinAdapter;
12
+ defaults?: Partial<Omit<RunMartinInput, "adapter">>;
13
+ }
14
+
15
+ export type MartinLoopRunInput = Omit<RunMartinInput, "adapter"> & {
16
+ adapter?: MartinAdapter;
8
17
  };
9
- export type MartinLoopFacade = typeof MartinLoop;
18
+
19
+ export declare class MartinLoop {
20
+ constructor(options?: MartinLoopOptions);
21
+ run(input: MartinLoopRunInput): Promise<RunMartinResult>;
22
+ }
package/dist/index.js CHANGED
@@ -1,9 +1,31 @@
1
- import { runMartin } from "@martin/core";
2
- export * from "@martin/core";
3
- export * from "@martin/adapters";
4
- export * from "@martin/sdk";
5
- export { executeCli, parseCliArguments, renderCliHelp } from "@martin/cli";
6
- export const MartinLoop = {
7
- run: runMartin
8
- };
9
- //# sourceMappingURL=index.js.map
1
+ import { runMartin } from "./vendor/core/index.js";
2
+
3
+ export { runMartin, compilePromptPacket, createFileRunStore, makeLedgerEvent, resolveRunsRoot } from "./vendor/core/index.js";
4
+ export { executeCli, parseCliArguments, renderCliHelp } from "./vendor/cli/index.js";
5
+ export { createClaudeCliAdapter, createCodexCliAdapter, createDirectProviderAdapter, createStubDirectProviderAdapter, createStubAgentCliAdapter } from "./vendor/adapters/index.js";
6
+ export { appendLoopEvent, buildPortfolioSnapshot, createGovernanceSnapshot, createLoopRecord, createTelemetryEnvelope, DEFAULT_BUDGET, EMPTY_COST, validateTelemetryBatch, validateTelemetryEnvelope } from "./vendor/contracts/index.js";
7
+
8
+ export class MartinLoop {
9
+ constructor(options = {}) {
10
+ this.adapter = options.adapter;
11
+ this.defaults = options.defaults ?? {};
12
+ }
13
+
14
+ async run(input) {
15
+ const merged = {
16
+ ...this.defaults,
17
+ ...input,
18
+ metadata: {
19
+ ...(this.defaults.metadata ?? {}),
20
+ ...(input.metadata ?? {}),
21
+ },
22
+ adapter: input.adapter ?? this.adapter,
23
+ };
24
+
25
+ if (!merged.adapter) {
26
+ throw new Error("MartinLoop.run requires an adapter. Import an adapter helper from \"martin-loop\" or pass a MartinAdapter instance.");
27
+ }
28
+
29
+ return runMartin(merged);
30
+ }
31
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Real agent-CLI adapters.
3
+ *
4
+ * Exports a generic factory (`createAgentCliAdapter`) and two pre-configured
5
+ * factories (`createClaudeCliAdapter`, `createCodexCliAdapter`) that spawn
6
+ * the respective AI coding CLI as a child subprocess.
7
+ *
8
+ * Usage in CLI:
9
+ * createClaudeCliAdapter({ workingDirectory: process.cwd() })
10
+ * createCodexCliAdapter({ workingDirectory: process.cwd() })
11
+ *
12
+ * MCP tools and integration tests use the same factories.
13
+ */
14
+ import type { MartinAdapter } from "../core/index.js";
15
+ import { type SpawnLike } from "./cli-bridge.js";
16
+ /**
17
+ * Given a prompt string, returns the full argv array to pass to spawn().
18
+ * Example for Claude: (p) => ["--print", p, "--dangerously-skip-permissions"]
19
+ * Example for Codex: (p) => ["--full-auto", p]
20
+ */
21
+ export type CliArgsBuilder = (prompt: string) => string[];
22
+ export interface AgentCliAdapterOptions {
23
+ /** The executable to spawn (e.g. "claude", "codex"). */
24
+ command: string;
25
+ /** Converts a prompt string into the argv array passed to spawn(). */
26
+ argsBuilder: CliArgsBuilder;
27
+ /** Adapter ID suffix. Defaults to command. */
28
+ adapterIdSuffix?: string;
29
+ /** Working directory for all subprocesses. Defaults to process.cwd(). */
30
+ workingDirectory?: string;
31
+ /** Timeout for the agent subprocess in ms. Defaults to 300_000 (5 min). */
32
+ timeoutMs?: number;
33
+ /** Timeout per verification command in ms. Defaults to 60_000 (1 min). */
34
+ verifyTimeoutMs?: number;
35
+ /** Human-readable label shown in loop records. */
36
+ label?: string;
37
+ /** Model name surfaced in adapter metadata (also used for cost estimation). */
38
+ model?: string;
39
+ /**
40
+ * Whether the CLI outputs JSON when --output-format json is passed.
41
+ * Set to false for CLIs that don't support this flag (e.g. Codex).
42
+ * Defaults to true for Claude.
43
+ */
44
+ supportsJsonOutput?: boolean;
45
+ /** Test-only override for subprocess spawning. */
46
+ spawnImpl?: SpawnLike;
47
+ }
48
+ export interface ClaudeCliAdapterOptions {
49
+ workingDirectory?: string;
50
+ timeoutMs?: number;
51
+ verifyTimeoutMs?: number;
52
+ label?: string;
53
+ /** Override the model passed via --model flag. */
54
+ model?: string;
55
+ /** Extra args appended after core args (before prompt). */
56
+ extraArgs?: string[];
57
+ spawnImpl?: SpawnLike;
58
+ }
59
+ export interface CodexCliAdapterOptions {
60
+ workingDirectory?: string;
61
+ timeoutMs?: number;
62
+ verifyTimeoutMs?: number;
63
+ label?: string;
64
+ /** Override the model passed via --model flag. */
65
+ model?: string;
66
+ /** Run in full-auto mode (--full-auto). Defaults to true. */
67
+ fullAuto?: boolean;
68
+ /** Extra args appended after core args (before prompt). */
69
+ extraArgs?: string[];
70
+ spawnImpl?: SpawnLike;
71
+ }
72
+ export declare function createAgentCliAdapter(options: AgentCliAdapterOptions): MartinAdapter;
73
+ /**
74
+ * Spawns `claude --output-format json --print "<prompt>" --dangerously-skip-permissions [extraArgs]`.
75
+ *
76
+ * The --output-format json flag causes Claude CLI to return structured JSON
77
+ * including real token usage counts, enabling accurate cost tracking.
78
+ *
79
+ * Requires the Claude Code CLI to be installed and authenticated:
80
+ * https://docs.anthropic.com/claude-code
81
+ */
82
+ export declare function createClaudeCliAdapter(options?: ClaudeCliAdapterOptions): MartinAdapter;
83
+ /**
84
+ * Spawns `codex [--full-auto] [--model <model>] "<prompt>" [extraArgs]`.
85
+ *
86
+ * Requires the Codex CLI to be installed and authenticated:
87
+ * npm install -g @openai/codex
88
+ */
89
+ export declare function createCodexCliAdapter(options?: CodexCliAdapterOptions): MartinAdapter;