@mandible-ai/mandible 0.2.0 → 0.3.1

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 (101) hide show
  1. package/README.md +169 -58
  2. package/dist/examples/code-pipeline/colonies.d.ts +10 -0
  3. package/dist/examples/code-pipeline/colonies.d.ts.map +1 -0
  4. package/dist/examples/code-pipeline/colonies.js +112 -0
  5. package/dist/examples/code-pipeline/colonies.js.map +1 -0
  6. package/dist/examples/code-pipeline/docker.d.ts +3 -0
  7. package/dist/examples/code-pipeline/docker.d.ts.map +1 -0
  8. package/dist/examples/code-pipeline/docker.js +63 -0
  9. package/dist/examples/code-pipeline/docker.js.map +1 -0
  10. package/dist/examples/code-pipeline/index.js +44 -228
  11. package/dist/examples/code-pipeline/index.js.map +1 -1
  12. package/dist/examples/code-pipeline/with-providers.js +1 -2
  13. package/dist/examples/code-pipeline/with-providers.js.map +1 -1
  14. package/dist/examples/github-colony/mandible.config.d.ts +1 -10
  15. package/dist/examples/github-colony/mandible.config.d.ts.map +1 -1
  16. package/dist/examples/github-colony/mandible.config.js +16 -24
  17. package/dist/examples/github-colony/mandible.config.js.map +1 -1
  18. package/dist/examples/repo-maintenance/fixer.d.ts +11 -4
  19. package/dist/examples/repo-maintenance/fixer.d.ts.map +1 -1
  20. package/dist/examples/repo-maintenance/fixer.js +130 -123
  21. package/dist/examples/repo-maintenance/fixer.js.map +1 -1
  22. package/dist/examples/repo-maintenance/mandible.config.d.ts +1 -10
  23. package/dist/examples/repo-maintenance/mandible.config.d.ts.map +1 -1
  24. package/dist/examples/repo-maintenance/mandible.config.js +14 -14
  25. package/dist/examples/repo-maintenance/mandible.config.js.map +1 -1
  26. package/dist/examples/repo-maintenance/scout.d.ts +11 -4
  27. package/dist/examples/repo-maintenance/scout.d.ts.map +1 -1
  28. package/dist/examples/repo-maintenance/scout.js +102 -95
  29. package/dist/examples/repo-maintenance/scout.js.map +1 -1
  30. package/dist/examples/repo-maintenance/seed.js +19 -37
  31. package/dist/examples/repo-maintenance/seed.js.map +1 -1
  32. package/dist/src/cloud/client.d.ts +1 -1
  33. package/dist/src/cloud/client.d.ts.map +1 -1
  34. package/dist/src/cloud/client.js +1 -1
  35. package/dist/src/cloud/client.js.map +1 -1
  36. package/dist/src/cloud/index.d.ts +1 -3
  37. package/dist/src/cloud/index.d.ts.map +1 -1
  38. package/dist/src/cloud/index.js +0 -1
  39. package/dist/src/cloud/index.js.map +1 -1
  40. package/dist/src/cloud/types.d.ts +5 -9
  41. package/dist/src/cloud/types.d.ts.map +1 -1
  42. package/dist/src/core/types.d.ts +43 -0
  43. package/dist/src/core/types.d.ts.map +1 -1
  44. package/dist/src/core/types.js +10 -0
  45. package/dist/src/core/types.js.map +1 -1
  46. package/dist/src/dsl/index.d.ts +1 -0
  47. package/dist/src/dsl/index.d.ts.map +1 -1
  48. package/dist/src/dsl/index.js +1 -0
  49. package/dist/src/dsl/index.js.map +1 -1
  50. package/dist/src/dsl/mandible.d.ts +62 -0
  51. package/dist/src/dsl/mandible.d.ts.map +1 -0
  52. package/dist/src/dsl/mandible.js +140 -0
  53. package/dist/src/dsl/mandible.js.map +1 -0
  54. package/dist/src/environments/filesystem/adapter.d.ts.map +1 -1
  55. package/dist/src/environments/filesystem/adapter.js.map +1 -1
  56. package/dist/src/hosts/docker.d.ts +67 -0
  57. package/dist/src/hosts/docker.d.ts.map +1 -0
  58. package/dist/src/hosts/docker.js +135 -0
  59. package/dist/src/hosts/docker.js.map +1 -0
  60. package/dist/src/hosts/index.d.ts +5 -0
  61. package/dist/src/hosts/index.d.ts.map +1 -0
  62. package/dist/src/hosts/index.js +3 -0
  63. package/dist/src/hosts/index.js.map +1 -0
  64. package/dist/src/hosts/local.d.ts +41 -0
  65. package/dist/src/hosts/local.d.ts.map +1 -0
  66. package/dist/src/hosts/local.js +84 -0
  67. package/dist/src/hosts/local.js.map +1 -0
  68. package/dist/src/index.d.ts +8 -3
  69. package/dist/src/index.d.ts.map +1 -1
  70. package/dist/src/index.js +8 -1
  71. package/dist/src/index.js.map +1 -1
  72. package/dist/src/providers/claude-code.d.ts.map +1 -1
  73. package/dist/src/providers/claude-code.js +3 -5
  74. package/dist/src/providers/claude-code.js.map +1 -1
  75. package/dist/src/providers/types.d.ts +0 -9
  76. package/dist/src/providers/types.d.ts.map +1 -1
  77. package/package.json +11 -6
  78. package/dist/examples/docker-pipeline/index.d.ts +0 -3
  79. package/dist/examples/docker-pipeline/index.d.ts.map +0 -1
  80. package/dist/examples/docker-pipeline/index.js +0 -235
  81. package/dist/examples/docker-pipeline/index.js.map +0 -1
  82. package/dist/examples/remote-pipeline/index.d.ts +0 -3
  83. package/dist/examples/remote-pipeline/index.d.ts.map +0 -1
  84. package/dist/examples/remote-pipeline/index.js +0 -154
  85. package/dist/examples/remote-pipeline/index.js.map +0 -1
  86. package/dist/src/environments/remote/adapter.d.ts +0 -61
  87. package/dist/src/environments/remote/adapter.d.ts.map +0 -1
  88. package/dist/src/environments/remote/adapter.js +0 -392
  89. package/dist/src/environments/remote/adapter.js.map +0 -1
  90. package/dist/src/environments/remote/index.d.ts +0 -5
  91. package/dist/src/environments/remote/index.d.ts.map +0 -1
  92. package/dist/src/environments/remote/index.js +0 -3
  93. package/dist/src/environments/remote/index.js.map +0 -1
  94. package/dist/src/environments/remote/protocol.d.ts +0 -124
  95. package/dist/src/environments/remote/protocol.d.ts.map +0 -1
  96. package/dist/src/environments/remote/protocol.js +0 -24
  97. package/dist/src/environments/remote/protocol.js.map +0 -1
  98. package/dist/src/providers/agent.d.ts +0 -23
  99. package/dist/src/providers/agent.d.ts.map +0 -1
  100. package/dist/src/providers/agent.js +0 -184
  101. package/dist/src/providers/agent.js.map +0 -1
package/README.md CHANGED
@@ -27,43 +27,110 @@ Stigmergy sidesteps all of that. The environment carries the state. Agents are s
27
27
  ## Quick start
28
28
 
29
29
  ```bash
30
- npm install mandible
30
+ npm install @mandible-ai/mandible
31
31
  ```
32
32
 
33
33
  ```typescript
34
- import { colony, createRuntime, FilesystemEnvironment, withClaudeCode } from 'mandible';
34
+ import { mandible, FilesystemEnvironment } from '@mandible-ai/mandible';
35
35
 
36
36
  const env = new FilesystemEnvironment({ root: './.mandible/signals' });
37
37
 
38
- const shaper = colony('shaper')
39
- .in(env)
40
- .sense('task:ready', { unclaimed: true })
41
- .do(withClaudeCode({
42
- systemPrompt: 'You are a code shaper. Given a task, write the implementation.',
43
- allowedTools: ['Read', 'Write', 'Bash'],
44
- }))
45
- .concurrency(2)
46
- .claim('lease', 30_000)
47
- .build();
38
+ const host = await mandible('code-review')
39
+ .environment(env)
40
+ .colony('shaper', c => c
41
+ .sense('task:ready', { unclaimed: true })
42
+ .do('shape-code', async (signal, ctx) => {
43
+ const result = await shapeCode(signal.payload);
44
+ await ctx.deposit('artifact:shaped', result, { causedBy: [signal.id] });
45
+ await ctx.withdraw(signal.id);
46
+ })
47
+ .concurrency(2)
48
+ .claim('lease', 30_000)
49
+ )
50
+ .colony('critic', c => c
51
+ .sense('artifact:shaped', { unclaimed: true })
52
+ .do('review-code', async (signal, ctx) => {
53
+ const review = await reviewCode(signal.payload);
54
+ await ctx.deposit('review:approved', review, { causedBy: [signal.id] });
55
+ await ctx.withdraw(signal.id);
56
+ })
57
+ .claim('exclusive')
58
+ )
59
+ .start();
60
+ ```
61
+
62
+ No colony references any other colony. They coordinate entirely through signals in the environment.
63
+
64
+ ### Hosting models
65
+
66
+ The **environment** (where signals live) is orthogonal to the **host** (where colony code runs). Colony definitions stay the same across all hosts — only the `.host()` call changes.
67
+
68
+ #### Local (default)
48
69
 
49
- const critic = colony('critic')
50
- .in(env)
51
- .sense('task:shaped', { unclaimed: true })
52
- .do(withClaudeCode({
53
- systemPrompt: 'You are a code critic. Review the implementation for correctness and style.',
54
- allowedTools: ['Read'],
70
+ Runs colonies as Node runtimes in the current process. This is the default when `.host()` is omitted:
71
+
72
+ ```typescript
73
+ import { mandible, FilesystemEnvironment } from '@mandible-ai/mandible';
74
+
75
+ const env = new FilesystemEnvironment({ root: './.mandible/signals' });
76
+
77
+ const host = await mandible('code-pipeline')
78
+ .environment(env)
79
+ .colony('shaper', shaper)
80
+ .colony('critic', critic)
81
+ .colony('keeper', keeper)
82
+ .start();
83
+
84
+ await host.stop();
85
+ ```
86
+
87
+ #### Docker
88
+
89
+ Runs each colony as a Docker container via the Mandible Cloud API:
90
+
91
+ ```typescript
92
+ import { mandible, FilesystemEnvironment, docker } from '@mandible-ai/mandible';
93
+
94
+ const env = new FilesystemEnvironment({ root: './.mandible/signals' });
95
+
96
+ const host = await mandible('code-pipeline')
97
+ .environment(env)
98
+ .host(docker({
99
+ apiUrl: process.env.MANDIBLE_API_URL!,
100
+ apiKey: process.env.MANDIBLE_API_KEY!,
101
+ image: 'mandible-colony:latest',
55
102
  }))
56
- .claim('exclusive')
57
- .build();
103
+ .colony('shaper', shaper)
104
+ .colony('critic', critic)
105
+ .colony('keeper', keeper)
106
+ .start();
58
107
 
59
- // Start them — they self-organize from here
60
- const shaperRuntime = createRuntime(shaper);
61
- const criticRuntime = createRuntime(critic);
62
- await shaperRuntime.start();
63
- await criticRuntime.start();
108
+ console.log(host.metadata.projectId);
109
+ await host.stop();
64
110
  ```
65
111
 
66
- No colony references any other colony. They coordinate entirely through signals in the environment.
112
+ #### Cloud (Edera microVMs)
113
+
114
+ For production workloads, run colonies in isolated Edera zones via [Mandible Cloud](https://mandible.dev):
115
+
116
+ ```typescript
117
+ import { mandible, FilesystemEnvironment } from '@mandible-ai/mandible';
118
+ import { cloud } from '@mandible-ai/cloud';
119
+
120
+ const env = new FilesystemEnvironment({ root: './.mandible/signals' });
121
+
122
+ const host = await mandible('code-pipeline')
123
+ .environment(env)
124
+ .host(cloud({ apiKey: process.env.MANDIBLE_API_KEY!, project: 'code-review' }))
125
+ .colony('shaper', shaper)
126
+ .colony('critic', critic)
127
+ .colony('keeper', keeper)
128
+ .start();
129
+
130
+ await host.stop();
131
+ ```
132
+
133
+ Same colonies, same environment, different host.
67
134
 
68
135
  ### Run with the dashboard
69
136
 
@@ -134,14 +201,37 @@ sense → match rules → claim → execute action → deposit → (others sense
134
201
 
135
202
  Other colonies sense those deposited signals and the cycle continues. Complex workflows emerge from simple local rules.
136
203
 
137
- ## Colony DSL
204
+ ## Mandible DSL
205
+
206
+ The `mandible()` function is the top-level entry point for defining and starting multi-colony systems:
207
+
208
+ ```typescript
209
+ const host = await mandible('my-swarm')
210
+ .environment(env) // where colonies operate
211
+ .colony('name', c => c // define a colony inline
212
+ .sense('type:pattern', { unclaimed: true }) // what to watch for
213
+ .do('action-name', handler) // what to do
214
+ .concurrency(3) // max parallel agents
215
+ .claim('lease', 30_000) // claim strategy
216
+ )
217
+ .start(); // start everything
218
+ ```
219
+
220
+ `start()` delegates to the host — `local()` starts Node runtimes in the current process, `docker()` launches containers, `cloud()` launches Edera microVMs. Returns the host for lifecycle control (`host.stop()`, `host.dashboard()`).
221
+
222
+ ### Colony builder
223
+
224
+ For lower-level control, use the `colony()` builder directly:
138
225
 
139
226
  ```typescript
140
227
  colony('name')
141
228
  .in(env) // which environment
142
229
  .sense('type:pattern', { unclaimed: true }) // what to watch for
143
230
  .when(signal => signal.payload.priority > 0) // optional guard
144
- .do(withClaudeCode({ allowedTools: ['Read', 'Write'] })) // action provider
231
+ .do('shape', withClaudeCode({ // action provider
232
+ prompt: signal => `Implement: ${signal.payload.name}`,
233
+ allowedTools: ['Read', 'Write'],
234
+ }))
145
235
  .concurrency(3) // max parallel agents
146
236
  .claim('lease', 30_000) // claim strategy
147
237
  .poll(2000) // sensor poll interval (ms)
@@ -204,7 +294,7 @@ Any shared substrate that supports observe/deposit/withdraw/claim/watch can be a
204
294
  Signals are JSON files. Claims use atomic file operations. History lives in a `withdrawn/` directory.
205
295
 
206
296
  ```typescript
207
- import { FilesystemEnvironment } from 'mandible';
297
+ import { FilesystemEnvironment } from '@mandible-ai/mandible';
208
298
 
209
299
  const env = new FilesystemEnvironment({
210
300
  root: './.mandible/signals',
@@ -217,7 +307,7 @@ const env = new FilesystemEnvironment({
217
307
  Issues, pull requests, comments, and labels mapped as signals. Colonies can sense repository activity and deposit responses.
218
308
 
219
309
  ```typescript
220
- import { GitHubEnvironment } from 'mandible';
310
+ import { GitHubEnvironment } from '@mandible-ai/mandible';
221
311
 
222
312
  const env = new GitHubEnvironment({
223
313
  owner: 'mandible-ai',
@@ -226,21 +316,6 @@ const env = new GitHubEnvironment({
226
316
  });
227
317
  ```
228
318
 
229
- ### Remote (implemented)
230
-
231
- WebSocket-based environment for distributed deployments. Multiple machines share a single signal namespace over the network.
232
-
233
- ```typescript
234
- import { RemoteEnvironment } from 'mandible';
235
-
236
- const env = new RemoteEnvironment({
237
- url: 'ws://coordinator:4041',
238
- apiKey: process.env.MANDIBLE_API_KEY,
239
- project: 'my-project',
240
- name: 'distributed',
241
- });
242
- ```
243
-
244
319
  ### Dolt (stubbed)
245
320
 
246
321
  [Dolt](https://www.dolthub.com/) is a SQL database with Git-like versioning. Signals become rows, branching enables parallel work, and `dolt_history` provides queryable time travel for the full signal history.
@@ -264,6 +339,22 @@ interface Environment {
264
339
  }
265
340
  ```
266
341
 
342
+ Hosts are orthogonal to Environments. To run colonies somewhere other than the local process, implement the `Host` interface:
343
+
344
+ ```typescript
345
+ interface Host {
346
+ name: string;
347
+ start(colonies: ColonyDefinition[]): Promise<void>;
348
+ stop(): Promise<void>;
349
+ dashboard(options?: DashboardOptions): Promise<void>;
350
+ metadata: HostMetadata;
351
+ colonies: Array<{ name: string; state: string }>;
352
+ environments: Environment[];
353
+ }
354
+ ```
355
+
356
+ Built-in hosts: `local()` (in-process), `docker()` (containers). Cloud hosts live in `@mandible-ai/cloud`.
357
+
267
358
  ## Patterns
268
359
 
269
360
  Reusable coordination patterns built on top of the core primitives.
@@ -273,7 +364,7 @@ Reusable coordination patterns built on top of the core primitives.
273
364
  Cross-environment signal mirroring with attestation chains. Bridges watch for signals in one environment and mirror them to another, appending a signed attestation to preserve provenance across boundaries.
274
365
 
275
366
  ```typescript
276
- import { createBridge } from 'mandible';
367
+ import { createBridge } from '@mandible-ai/mandible';
277
368
 
278
369
  const bridge = createBridge({
279
370
  name: 'local-to-github',
@@ -290,7 +381,7 @@ await bridge.start();
290
381
  Trust monitoring colony that watches an environment for signals with invalid or missing provenance. When violations are detected, the sentinel deposits `trust:violation` report signals that other colonies can react to.
291
382
 
292
383
  ```typescript
293
- import { createSentinel } from 'mandible';
384
+ import { createSentinel } from '@mandible-ai/mandible';
294
385
 
295
386
  const sentinel = createSentinel({
296
387
  name: 'trust-guard',
@@ -317,11 +408,14 @@ src/
317
408
  attestation.ts Ed25519 signing & verification (@noble/ed25519)
318
409
  dsl/
319
410
  builder.ts Fluent colony definition DSL
411
+ mandible.ts mandible() — multi-colony orchestration + start
320
412
  environments/
321
413
  filesystem/ Filesystem adapter (JSON files + atomic claims)
322
414
  github/ GitHub adapter (issues, PRs, comments, labels as signals)
323
- remote/ Remote adapter (WebSocket-based distributed environments)
324
415
  dolt/ Dolt adapter (stub)
416
+ hosts/
417
+ local.ts LocalHost — runs colonies in current process
418
+ docker.ts DockerHost — runs colonies as Docker containers
325
419
  providers/
326
420
  claude-code.ts withClaudeCode — Claude Code SDK (live)
327
421
  structured-output.ts withStructuredOutput — multi-model
@@ -333,12 +427,17 @@ src/
333
427
 
334
428
  tests/
335
429
  core/ Signal, runtime, attestation tests
336
- environments/ Filesystem, GitHub, remote adapter tests
430
+ environments/ Filesystem, GitHub adapter tests
431
+ dsl/ DSL and mandible() builder tests
337
432
  providers/ Agent, structured output, bash provider tests
338
433
  colonies/ Integration tests for colony workflows
339
434
 
340
435
  examples/
341
- code-pipeline/ Shaper → Critic → Keeper pipeline demo
436
+ code-pipeline/
437
+ colonies.ts Shared colony definitions (shaper, critic, keeper)
438
+ index.ts Local host — runs in current process
439
+ docker.ts Docker host — runs as containers
440
+ with-providers.ts Real LLM providers (Claude Code, Anthropic, Bash)
342
441
  repo-maintenance/ Scout + Fixer repo maintenance demo
343
442
  ```
344
443
 
@@ -346,16 +445,26 @@ examples/
346
445
 
347
446
  ### Code pipeline
348
447
 
349
- The included demo seeds 5 coding tasks into a filesystem environment. Three colonies self-organize to process them:
448
+ Three colonies coordinate through a shared filesystem environment:
350
449
 
351
- - **Shaper** (concurrency: 2) — picks up `task:ready` signals, produces `task:shaped` signals
352
- - **Critic** (concurrency: 2) — reviews shaped artifacts, deposits `review:approved` or `review:rejected`
353
- - **Keeper** (concurrency: 1) — commits approved work, deposits `task:complete`
450
+ - **Shaper** (concurrency: 2) — picks up `task:ready` signals, produces `artifact:shaped`
451
+ - **Critic** (concurrency: 2) — reviews shaped artifacts, deposits `review:approved` or `review:changes-needed`
452
+ - **Keeper** (concurrency: 1) — merges approved work, deposits `artifact:merged`
354
453
 
355
- No orchestrator. No message broker. No routing logic. The colonies discover work through the environment and coordinate through signals.
454
+ Colony definitions live in `colonies.ts` and are shared across all hosting modes:
356
455
 
357
456
  ```bash
358
- npm run demo
457
+ # Local host (default)
458
+ npx tsx examples/code-pipeline/index.ts
459
+
460
+ # Docker host
461
+ export MANDIBLE_API_URL=http://localhost:9091
462
+ export MANDIBLE_API_KEY=your-key
463
+ npx tsx examples/code-pipeline/docker.ts
464
+
465
+ # With real LLM providers
466
+ export ANTHROPIC_API_KEY=sk-ant-...
467
+ npx tsx examples/code-pipeline/with-providers.ts
359
468
  ```
360
469
 
361
470
  ### Repo maintenance
@@ -375,9 +484,11 @@ Both colonies are wired to real Claude agents via `withClaudeCode`. The dashboar
375
484
 
376
485
  - [x] `mandible dev` CLI + live dashboard
377
486
  - [x] `withClaudeCode` wired to Claude Code SDK
378
- - [x] Test suite (371 tests, 95%+ coverage)
487
+ - [x] Test suite (378 tests, 95%+ coverage)
379
488
  - [x] GitHub environment adapter
380
- - [x] Remote environment adapter
489
+ - [x] `mandible()` DSL with Host/Environment separation
490
+ - [x] `local()` and `docker()` host implementations
491
+ - [ ] `@mandible-ai/cloud` — run colonies in Edera microVMs via Mandible Cloud
381
492
  - [ ] `create-mandible` starter template
382
493
  - [ ] Dashboard GIF + landing page
383
494
  - [ ] Dolt full implementation
@@ -0,0 +1,10 @@
1
+ import type { ColonyBuilder } from '../../src/dsl/builder.js';
2
+ export declare function shaper(c: ColonyBuilder): ColonyBuilder<Record<string, unknown>>;
3
+ export declare function critic(c: ColonyBuilder): ColonyBuilder<Record<string, unknown>>;
4
+ export declare function keeper(c: ColonyBuilder): ColonyBuilder<Record<string, unknown>>;
5
+ export declare const SEED_TASKS: {
6
+ name: string;
7
+ priority: string;
8
+ description: string;
9
+ }[];
10
+ //# sourceMappingURL=colonies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colonies.d.ts","sourceRoot":"","sources":["../../../examples/code-pipeline/colonies.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAiC9D,wBAAgB,MAAM,CAAC,CAAC,EAAE,aAAa,0CAgBtC;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,aAAa,0CA+BtC;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,aAAa,0CAiBtC;AAED,eAAO,MAAM,UAAU;;;;GAMtB,CAAC"}
@@ -0,0 +1,112 @@
1
+ // ============================================================
2
+ // Shared Colony Definitions — Shaper / Critic / Keeper
3
+ // ============================================================
4
+ // These colonies are reusable across any host (local, docker,
5
+ // cloud). They define *what* happens, not *where* it runs.
6
+ //
7
+ // Each colony only knows about signal types — no colony
8
+ // references any other colony. Coordination emerges from
9
+ // the shared signal environment.
10
+ // ============================================================
11
+ function sleep(ms) {
12
+ return new Promise(resolve => setTimeout(resolve, ms));
13
+ }
14
+ async function simulateShaping(task) {
15
+ await sleep(500 + Math.random() * 1500);
16
+ return {
17
+ code: `function ${task.name}() { return true; }`,
18
+ linesChanged: Math.floor(Math.random() * 100) + 10,
19
+ task: task.name,
20
+ };
21
+ }
22
+ async function simulateReview(artifact) {
23
+ await sleep(300 + Math.random() * 1000);
24
+ const approved = Math.random() > 0.2;
25
+ return {
26
+ approved,
27
+ feedback: approved
28
+ ? `Code for "${artifact.task}" looks good.`
29
+ : `Code for "${artifact.task}" needs error handling.`,
30
+ };
31
+ }
32
+ async function simulateMerge(artifact) {
33
+ await sleep(200 + Math.random() * 500);
34
+ return { merged: true, task: artifact.task, commitHash: Math.random().toString(36).slice(2, 10) };
35
+ }
36
+ // Colony configurators — passed to mandible().colony(name, configure)
37
+ export function shaper(c) {
38
+ return c
39
+ .sense('task:ready', { unclaimed: true, minConcentration: 0.1 })
40
+ .do('shape-code', async (signal, ctx) => {
41
+ ctx.log(`Shaping: ${signal.payload.name}`);
42
+ const artifact = await simulateShaping(signal.payload);
43
+ await ctx.deposit('artifact:shaped', artifact, {
44
+ causedBy: [signal.id],
45
+ tags: ['needs-review'],
46
+ });
47
+ await ctx.withdraw(signal.id);
48
+ ctx.log(`Shaped "${signal.payload.name}" (${artifact.linesChanged} lines)`);
49
+ })
50
+ .concurrency(2)
51
+ .claim('lease', 30_000)
52
+ .poll(1000);
53
+ }
54
+ export function critic(c) {
55
+ return c
56
+ .sense('artifact:shaped', { unclaimed: true, minConcentration: 0.1 })
57
+ .do('review-code', async (signal, ctx) => {
58
+ ctx.log(`Reviewing: ${signal.payload.task}`);
59
+ const review = await simulateReview(signal.payload);
60
+ if (review.approved) {
61
+ await ctx.deposit('review:approved', {
62
+ artifact: signal.payload,
63
+ feedback: review.feedback,
64
+ }, {
65
+ causedBy: [signal.id],
66
+ tags: ['ready-to-merge'],
67
+ });
68
+ ctx.log(`Approved: ${review.feedback}`);
69
+ }
70
+ else {
71
+ await ctx.deposit('review:changes-needed', {
72
+ artifact: signal.payload,
73
+ feedback: review.feedback,
74
+ }, {
75
+ causedBy: [signal.id],
76
+ tags: ['needs-rework'],
77
+ ttl: 60_000,
78
+ });
79
+ ctx.log(`Changes needed: ${review.feedback}`);
80
+ }
81
+ await ctx.withdraw(signal.id);
82
+ })
83
+ .concurrency(2)
84
+ .claim('lease', 30_000)
85
+ .poll(1000);
86
+ }
87
+ export function keeper(c) {
88
+ return c
89
+ .sense('review:approved', { unclaimed: true, minConcentration: 0.1 })
90
+ .do('merge-artifact', async (signal, ctx) => {
91
+ const artifact = signal.payload.artifact ?? {};
92
+ ctx.log(`Merging: ${artifact.task}`);
93
+ const result = await simulateMerge(artifact);
94
+ await ctx.deposit('artifact:merged', result, {
95
+ causedBy: [signal.id],
96
+ tags: ['complete'],
97
+ });
98
+ await ctx.withdraw(signal.id);
99
+ ctx.log(`Merged -> commit ${result.commitHash}`);
100
+ })
101
+ .concurrency(1)
102
+ .claim('exclusive')
103
+ .poll(1000);
104
+ }
105
+ export const SEED_TASKS = [
106
+ { name: 'auth-middleware', priority: 'high', description: 'Add JWT authentication' },
107
+ { name: 'rate-limiter', priority: 'medium', description: 'API rate limiting' },
108
+ { name: 'health-check', priority: 'low', description: 'Add /health endpoint' },
109
+ { name: 'error-handler', priority: 'high', description: 'Global error handling' },
110
+ { name: 'request-logger', priority: 'medium', description: 'Structured logging' },
111
+ ];
112
+ //# sourceMappingURL=colonies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colonies.js","sourceRoot":"","sources":["../../../examples/code-pipeline/colonies.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env tsx
2
+ export {};
3
+ //# sourceMappingURL=docker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../../../examples/code-pipeline/docker.ts"],"names":[],"mappings":""}
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env tsx
2
+ // ============================================================
3
+ // Code Pipeline — Docker Host
4
+ // ============================================================
5
+ // Same colonies as index.ts, but running as Docker containers
6
+ // via the Mandible Cloud API. The colony definitions are
7
+ // identical — only the host changes.
8
+ //
9
+ // Prerequisites:
10
+ // - Mandible Cloud API running (local or remote)
11
+ // - MANDIBLE_API_URL and MANDIBLE_API_KEY set
12
+ //
13
+ // To run:
14
+ // export MANDIBLE_API_URL=http://localhost:9091
15
+ // export MANDIBLE_API_KEY=your-api-key
16
+ // npx tsx examples/code-pipeline/docker.ts
17
+ // ============================================================
18
+ import { mandible, FilesystemEnvironment, docker } from '../../src/index.js';
19
+ import { shaper, critic, keeper, SEED_TASKS } from './colonies.js';
20
+ const apiUrl = process.env.MANDIBLE_API_URL;
21
+ const apiKey = process.env.MANDIBLE_API_KEY;
22
+ if (!apiUrl || !apiKey) {
23
+ console.error('Set MANDIBLE_API_URL and MANDIBLE_API_KEY');
24
+ process.exit(1);
25
+ }
26
+ const env = new FilesystemEnvironment({ root: '/tmp/mandible-demo', name: 'code-pipeline' });
27
+ // Same colonies, different host
28
+ const host = await mandible('code-pipeline')
29
+ .environment(env)
30
+ .host(docker({
31
+ apiUrl,
32
+ apiKey,
33
+ image: 'mandible-colony:latest',
34
+ }))
35
+ .colony('shaper', shaper)
36
+ .colony('critic', critic)
37
+ .colony('keeper', keeper)
38
+ .start();
39
+ const meta = host.metadata;
40
+ console.log(`Started ${host.colonies.length} colonies on ${host.name} host`);
41
+ console.log(`Project: ${meta.projectId}`);
42
+ console.log(`Signal server: ${meta.signalServerUrl}\n`);
43
+ // Seed tasks
44
+ for (const task of SEED_TASKS) {
45
+ await env.deposit({
46
+ type: 'task:ready',
47
+ payload: task,
48
+ meta: { deposited_by: 'seed', tags: [task.priority] },
49
+ });
50
+ console.log(` seeded: task:ready "${task.name}"`);
51
+ }
52
+ console.log('\nColonies running in Docker containers.');
53
+ console.log('Press Ctrl+C to stop.\n');
54
+ // Keep alive until interrupted
55
+ process.on('SIGINT', async () => {
56
+ console.log('\nStopping...');
57
+ await host.stop();
58
+ console.log('Stopped.');
59
+ process.exit(0);
60
+ });
61
+ // Block forever
62
+ await new Promise(() => { });
63
+ //# sourceMappingURL=docker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker.js","sourceRoot":"","sources":["../../../examples/code-pipeline/docker.ts"],"names":[],"mappings":";AACA,+DAA+D;AAC/D,8BAA8B;AAC9B,+DAA+D;AAC/D,8DAA8D;AAC9D,yDAAyD;AACzD,qCAAqC;AACrC,EAAE;AACF,iBAAiB;AACjB,mDAAmD;AACnD,gDAAgD;AAChD,EAAE;AACF,UAAU;AACV,kDAAkD;AAClD,yCAAyC;AACzC,6CAA6C;AAC7C,+DAA+D;AAE/D,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,EAA2B,MAAM,oBAAoB,CAAC;AACtG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEnE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;AAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;AAE5C,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;IACvB,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,GAAG,GAAG,IAAI,qBAAqB,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;AAE7F,gCAAgC;AAChC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,eAAe,CAAC;KACzC,WAAW,CAAC,GAAG,CAAC;KAChB,IAAI,CAAC,MAAM,CAAC;IACX,MAAM;IACN,MAAM;IACN,KAAK,EAAE,wBAAwB;CAChC,CAAC,CAAC;KACF,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC;KACxB,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC;KACxB,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC;KACxB,KAAK,EAAE,CAAC;AAEX,MAAM,IAAI,GAAG,IAAI,CAAC,QAA8B,CAAC;AACjD,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,QAAQ,CAAC,MAAM,gBAAgB,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC;AAC7E,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;AAC1C,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,CAAC,eAAe,IAAI,CAAC,CAAC;AAExD,aAAa;AACb,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;IAC9B,MAAM,GAAG,CAAC,OAAO,CAAC;QAChB,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;KACtD,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;AACrD,CAAC;AAED,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;AACxD,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;AAEvC,+BAA+B;AAC/B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;IAC9B,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC7B,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IAClB,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,gBAAgB;AAChB,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC"}