atomism 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/LICENSE +21 -0
- package/README.md +210 -0
- package/dist/chunk-34O5KJWR.js +81 -0
- package/dist/chunk-34O5KJWR.js.map +1 -0
- package/dist/chunk-55AP34JO.js +116 -0
- package/dist/chunk-55AP34JO.js.map +1 -0
- package/dist/chunk-6MDHM2B4.js +17 -0
- package/dist/chunk-6MDHM2B4.js.map +1 -0
- package/dist/chunk-GU2R4KLP.js +43 -0
- package/dist/chunk-GU2R4KLP.js.map +1 -0
- package/dist/chunk-H7WC3NXZ.js +39 -0
- package/dist/chunk-H7WC3NXZ.js.map +1 -0
- package/dist/chunk-P33CQFMY.js +329 -0
- package/dist/chunk-P33CQFMY.js.map +1 -0
- package/dist/chunk-P6X7T4KA.js +200 -0
- package/dist/chunk-P6X7T4KA.js.map +1 -0
- package/dist/chunk-PLQJM2KT.js +9 -0
- package/dist/chunk-PLQJM2KT.js.map +1 -0
- package/dist/chunk-RS2IEGW3.js +10 -0
- package/dist/chunk-RS2IEGW3.js.map +1 -0
- package/dist/chunk-S6Z5G5DB.js +84 -0
- package/dist/chunk-S6Z5G5DB.js.map +1 -0
- package/dist/chunk-UVUDQ4XP.js +259 -0
- package/dist/chunk-UVUDQ4XP.js.map +1 -0
- package/dist/chunk-UWVZQSP4.js +597 -0
- package/dist/chunk-UWVZQSP4.js.map +1 -0
- package/dist/chunk-YKJO3ZFY.js +308 -0
- package/dist/chunk-YKJO3ZFY.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +152 -0
- package/dist/cli.js.map +1 -0
- package/dist/create-atom-AXPDBYQL.js +153 -0
- package/dist/create-atom-AXPDBYQL.js.map +1 -0
- package/dist/escalate-BTEJT5NL.js +211 -0
- package/dist/escalate-BTEJT5NL.js.map +1 -0
- package/dist/extract-RPKCTINT.js +514 -0
- package/dist/extract-RPKCTINT.js.map +1 -0
- package/dist/graduate-453M7ZRQ.js +222 -0
- package/dist/graduate-453M7ZRQ.js.map +1 -0
- package/dist/helpers-PJPFPYBQ.js +11 -0
- package/dist/helpers-PJPFPYBQ.js.map +1 -0
- package/dist/history-OPD7NLZW.js +258 -0
- package/dist/history-OPD7NLZW.js.map +1 -0
- package/dist/import-generator-4CKRBMTE.js +1864 -0
- package/dist/import-generator-4CKRBMTE.js.map +1 -0
- package/dist/index.d.ts +230 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/init-2FINDMYK.js +741 -0
- package/dist/init-2FINDMYK.js.map +1 -0
- package/dist/list-NEBVBGG3.js +71 -0
- package/dist/list-NEBVBGG3.js.map +1 -0
- package/dist/parser-3BILOSOO.js +157 -0
- package/dist/parser-3BILOSOO.js.map +1 -0
- package/dist/plan-DNVARHWH.js +249 -0
- package/dist/plan-DNVARHWH.js.map +1 -0
- package/dist/register-XTRMSH7Y.js +91 -0
- package/dist/register-XTRMSH7Y.js.map +1 -0
- package/dist/revert-J4CRDE2K.js +87 -0
- package/dist/revert-J4CRDE2K.js.map +1 -0
- package/dist/run-3GI3SBYL.js +188 -0
- package/dist/run-3GI3SBYL.js.map +1 -0
- package/dist/scan-generators-ST4TBEY7.js +375 -0
- package/dist/scan-generators-ST4TBEY7.js.map +1 -0
- package/dist/signatures-K5QIL4WG.js +258 -0
- package/dist/signatures-K5QIL4WG.js.map +1 -0
- package/dist/skills-assign-IHOXX4AI.js +182 -0
- package/dist/skills-assign-IHOXX4AI.js.map +1 -0
- package/dist/skills-load-JSD5UG2K.js +20 -0
- package/dist/skills-load-JSD5UG2K.js.map +1 -0
- package/dist/skills-scan-WACJFRJN.js +25 -0
- package/dist/skills-scan-WACJFRJN.js.map +1 -0
- package/dist/skills-suggest-JFI2NUJI.js +269 -0
- package/dist/skills-suggest-JFI2NUJI.js.map +1 -0
- package/dist/status-KQVSAZFR.js +111 -0
- package/dist/status-KQVSAZFR.js.map +1 -0
- package/dist/suggest-IFFJQFIW.js +183 -0
- package/dist/suggest-IFFJQFIW.js.map +1 -0
- package/dist/test-HP3FG3MO.js +152 -0
- package/dist/test-HP3FG3MO.js.map +1 -0
- package/dist/test-gen-2ZGPOP35.js +347 -0
- package/dist/test-gen-2ZGPOP35.js.map +1 -0
- package/dist/trust-4R26DULG.js +248 -0
- package/dist/trust-4R26DULG.js.map +1 -0
- package/dist/validate-generator-46H2LYYQ.js +410 -0
- package/dist/validate-generator-46H2LYYQ.js.map +1 -0
- package/dist/workflow-5UVLBS7J.js +655 -0
- package/dist/workflow-5UVLBS7J.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1,741 @@
|
|
|
1
|
+
import {
|
|
2
|
+
withErrorHandling
|
|
3
|
+
} from "./chunk-GU2R4KLP.js";
|
|
4
|
+
import {
|
|
5
|
+
fileExists,
|
|
6
|
+
initStorage
|
|
7
|
+
} from "./chunk-YKJO3ZFY.js";
|
|
8
|
+
import {
|
|
9
|
+
toErrorMessage
|
|
10
|
+
} from "./chunk-PLQJM2KT.js";
|
|
11
|
+
|
|
12
|
+
// src/commands/init.ts
|
|
13
|
+
import { readFile as readFile3, writeFile as writeFile4, access } from "fs/promises";
|
|
14
|
+
import { join as join4 } from "path";
|
|
15
|
+
import { execSync } from "child_process";
|
|
16
|
+
|
|
17
|
+
// src/commands/skills-init.ts
|
|
18
|
+
import { mkdir, writeFile, stat } from "fs/promises";
|
|
19
|
+
import { join } from "path";
|
|
20
|
+
function generateSkillContent() {
|
|
21
|
+
return `---
|
|
22
|
+
name: atomic
|
|
23
|
+
description: Schema-first agent swarm orchestration framework
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# Atomic Framework
|
|
27
|
+
|
|
28
|
+
Schema-first agent swarm orchestration. Use atomic to define, execute, and evolve reusable capabilities.
|
|
29
|
+
|
|
30
|
+
## Trigger
|
|
31
|
+
|
|
32
|
+
Use this skill when:
|
|
33
|
+
- User mentions "atomic", "atom", "capability", or "workflow" in context of task orchestration
|
|
34
|
+
- User wants to create reusable, schema-validated tasks
|
|
35
|
+
- User wants to graduate patterns from probabilistic (AI) to deterministic (generator)
|
|
36
|
+
- Project has \`.atomic/\` directory
|
|
37
|
+
- User invokes \`/atomic\`
|
|
38
|
+
|
|
39
|
+
## Why Atoms?
|
|
40
|
+
|
|
41
|
+
Atoms solve a fundamental problem: **probabilistic work should become deterministic over time.**
|
|
42
|
+
|
|
43
|
+
When you write an API route the first time, it's creative work. The tenth time you write a similar route, it should be a template fill. But without tracking, you start from scratch every time.
|
|
44
|
+
|
|
45
|
+
Atoms provide:
|
|
46
|
+
1. **Schema enforcement** \u2014 Inputs/outputs are Zod-validated, not freeform
|
|
47
|
+
2. **Execution history** \u2014 Every run is recorded with inputs, outputs, success/failure
|
|
48
|
+
3. **Similarity detection** \u2014 AST-level comparison identifies when outputs converge on patterns
|
|
49
|
+
4. **Generator graduation** \u2014 When an atom produces 85%+ similar outputs, it can become a deterministic template
|
|
50
|
+
5. **Trust progression** \u2014 New capabilities require review; proven ones auto-execute
|
|
51
|
+
|
|
52
|
+
The goal: **Capture patterns once, replay deterministically forever.** Focus human attention on genuinely novel problems.
|
|
53
|
+
|
|
54
|
+
## When to Use Atoms
|
|
55
|
+
|
|
56
|
+
| Situation | Use |
|
|
57
|
+
|-----------|-----|
|
|
58
|
+
| One-off task, no verification needed | Direct code |
|
|
59
|
+
| Teaching Claude a capability | Claude Code skill |
|
|
60
|
+
| Repetitive task, same shape each time | **Atom** (extract or create) |
|
|
61
|
+
| Need trust gating / human review | **Atom with trust level** |
|
|
62
|
+
| Task should evolve to template | **Atom** (graduation path) |
|
|
63
|
+
| Always-on validation/enforcement | Hook |
|
|
64
|
+
|
|
65
|
+
**Proactive extraction**: When you notice doing the same thing 3+ times with the same shape, suggest: "This pattern would benefit from atomization \u2014 want me to extract it?"
|
|
66
|
+
|
|
67
|
+
Use \`atomic extract\` to create atoms from:
|
|
68
|
+
- Existing Claude Code skills (\`--skill\`)
|
|
69
|
+
- BMAD workflows (\`--bmad\`)
|
|
70
|
+
- MCP tool definitions (\`--mcp\`)
|
|
71
|
+
- Existing code files (\`--code\`)
|
|
72
|
+
|
|
73
|
+
## Directory Structure
|
|
74
|
+
|
|
75
|
+
\`\`\`
|
|
76
|
+
project/
|
|
77
|
+
\u251C\u2500\u2500 .atomic/ # Metadata and storage (auto-created by init)
|
|
78
|
+
\u2502 \u251C\u2500\u2500 registry.json # Registered atoms and capabilities
|
|
79
|
+
\u2502 \u251C\u2500\u2500 trust.json # Trust levels for capability stacks
|
|
80
|
+
\u2502 \u2514\u2500\u2500 db/ # SQLite storage for runs and artifacts
|
|
81
|
+
\u251C\u2500\u2500 .claude/
|
|
82
|
+
\u2502 \u2514\u2500\u2500 skills/
|
|
83
|
+
\u2502 \u2514\u2500\u2500 atomic/
|
|
84
|
+
\u2502 \u2514\u2500\u2500 SKILL.md # This skill (auto-created by init)
|
|
85
|
+
\u251C\u2500\u2500 atoms/ # Atom source files (default location)
|
|
86
|
+
\u2502 \u251C\u2500\u2500 my_atom.ts
|
|
87
|
+
\u2502 \u2514\u2500\u2500 my_atom.test.ts
|
|
88
|
+
\u2514\u2500\u2500 generators/ # Graduated generators (created by graduation)
|
|
89
|
+
\u2514\u2500\u2500 my_generator.ts
|
|
90
|
+
\`\`\`
|
|
91
|
+
|
|
92
|
+
## Core Concepts
|
|
93
|
+
|
|
94
|
+
### Atoms
|
|
95
|
+
The fundamental unit. A schema-validated, idempotent task with defined inputs/outputs.
|
|
96
|
+
|
|
97
|
+
\`\`\`typescript
|
|
98
|
+
// atoms/create_component.ts
|
|
99
|
+
import { defineAtom, success, executionError, z } from 'atomism';
|
|
100
|
+
|
|
101
|
+
export default defineAtom({
|
|
102
|
+
name: 'create_component',
|
|
103
|
+
description: 'Create a React component with tests',
|
|
104
|
+
input: z.object({
|
|
105
|
+
name: z.string().min(1),
|
|
106
|
+
type: z.enum(['functional', 'class']).default('functional'),
|
|
107
|
+
}),
|
|
108
|
+
output: z.object({
|
|
109
|
+
componentPath: z.string(),
|
|
110
|
+
testPath: z.string(),
|
|
111
|
+
}),
|
|
112
|
+
tests: { path: './create_component.test.ts' },
|
|
113
|
+
idempotent: true,
|
|
114
|
+
handler: async ({ name, type }) => {
|
|
115
|
+
// Implementation here
|
|
116
|
+
return success({ componentPath: '...', testPath: '...' });
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
\`\`\`
|
|
120
|
+
|
|
121
|
+
### Capabilities
|
|
122
|
+
Route requests to either an atom (probabilistic) or generator (deterministic).
|
|
123
|
+
|
|
124
|
+
- **Atom-backed**: AI executes with schema validation
|
|
125
|
+
- **Generator-backed**: Deterministic template execution
|
|
126
|
+
|
|
127
|
+
### Generators
|
|
128
|
+
Graduated atoms. When an atom produces similar outputs repeatedly, it can graduate to a generator (template-based, deterministic).
|
|
129
|
+
|
|
130
|
+
### Workflows
|
|
131
|
+
Compositions of capabilities with dependency resolution. Like Make/Terraform - declare dependencies, system resolves execution order.
|
|
132
|
+
|
|
133
|
+
### Trust Levels
|
|
134
|
+
- **new**: Requires human review
|
|
135
|
+
- **proven**: Track record of success, optional review
|
|
136
|
+
- **trusted**: Auto-execute without review
|
|
137
|
+
|
|
138
|
+
### Capability Stacks
|
|
139
|
+
Reusable groups of capabilities reviewed once, reused many times.
|
|
140
|
+
|
|
141
|
+
## Project Initialization
|
|
142
|
+
|
|
143
|
+
\`\`\`bash
|
|
144
|
+
# Initialize atomic in a project
|
|
145
|
+
atomic init
|
|
146
|
+
|
|
147
|
+
# Creates:
|
|
148
|
+
# .atomic/
|
|
149
|
+
# registry.json # Registered atoms and capabilities
|
|
150
|
+
# trust.json # Trust levels for capability stacks
|
|
151
|
+
# db/ # SQLite storage for runs and artifacts
|
|
152
|
+
\`\`\`
|
|
153
|
+
|
|
154
|
+
## Common Workflows
|
|
155
|
+
|
|
156
|
+
### 1. Register an Atom
|
|
157
|
+
|
|
158
|
+
\`\`\`bash
|
|
159
|
+
# Register a new atom
|
|
160
|
+
atomic register atoms/my_atom.ts
|
|
161
|
+
|
|
162
|
+
# Register with capability name
|
|
163
|
+
atomic register atoms/my_atom.ts --capability my_capability
|
|
164
|
+
\`\`\`
|
|
165
|
+
|
|
166
|
+
### 2. Run an Atom or Capability
|
|
167
|
+
|
|
168
|
+
\`\`\`bash
|
|
169
|
+
# Run by atom name
|
|
170
|
+
atomic run my_atom --input '{"key": "value"}'
|
|
171
|
+
|
|
172
|
+
# Run by capability name
|
|
173
|
+
atomic run my_capability --capability --input '{"key": "value"}'
|
|
174
|
+
|
|
175
|
+
# Skip confirmation for non-idempotent atoms
|
|
176
|
+
atomic run my_atom --input '{"key": "value"}' --yes
|
|
177
|
+
\`\`\`
|
|
178
|
+
|
|
179
|
+
### 3. Work with Workflows
|
|
180
|
+
|
|
181
|
+
\`\`\`bash
|
|
182
|
+
# List available workflows
|
|
183
|
+
atomic workflow list
|
|
184
|
+
|
|
185
|
+
# Run a workflow
|
|
186
|
+
atomic workflow run my_workflow
|
|
187
|
+
|
|
188
|
+
# Resume a failed workflow
|
|
189
|
+
atomic workflow resume my_workflow
|
|
190
|
+
|
|
191
|
+
# Preview execution plan
|
|
192
|
+
atomic plan my_workflow
|
|
193
|
+
\`\`\`
|
|
194
|
+
|
|
195
|
+
### 4. Graduate to Generator
|
|
196
|
+
|
|
197
|
+
When an atom produces consistent patterns:
|
|
198
|
+
|
|
199
|
+
\`\`\`bash
|
|
200
|
+
# Graduate a capability to generator
|
|
201
|
+
atomic graduate --capability my_capability
|
|
202
|
+
|
|
203
|
+
# Skip confirmation
|
|
204
|
+
atomic graduate --capability my_capability --yes
|
|
205
|
+
\`\`\`
|
|
206
|
+
|
|
207
|
+
### 5. Manage Trust
|
|
208
|
+
|
|
209
|
+
\`\`\`bash
|
|
210
|
+
# List all stacks with trust levels
|
|
211
|
+
atomic trust --list
|
|
212
|
+
|
|
213
|
+
# View specific stack
|
|
214
|
+
atomic trust my_stack
|
|
215
|
+
|
|
216
|
+
# Set trust level
|
|
217
|
+
atomic trust my_stack --level proven
|
|
218
|
+
|
|
219
|
+
# Reset to new
|
|
220
|
+
atomic trust my_stack --reset
|
|
221
|
+
\`\`\`
|
|
222
|
+
|
|
223
|
+
## Command Reference
|
|
224
|
+
|
|
225
|
+
| Command | Description |
|
|
226
|
+
|---------|-------------|
|
|
227
|
+
| \`atomic init\` | Initialize .atomic/ directory and skill |
|
|
228
|
+
| \`atomic register <path>\` | Register an atom file |
|
|
229
|
+
| \`atomic list\` | List atoms and capabilities |
|
|
230
|
+
| \`atomic run <target>\` | Execute atom or capability |
|
|
231
|
+
| \`atomic test <atom>\` | Run tests for an atom |
|
|
232
|
+
| \`atomic test-gen <path>\` | Generate structural tests |
|
|
233
|
+
| \`atomic extract\` | Create atom from skill/bmad/mcp/code |
|
|
234
|
+
| \`atomic workflow run <name>\` | Execute a workflow |
|
|
235
|
+
| \`atomic workflow list\` | List available workflows |
|
|
236
|
+
| \`atomic workflow resume <name>\` | Resume failed workflow |
|
|
237
|
+
| \`atomic plan <workflow>\` | Preview execution plan |
|
|
238
|
+
| \`atomic graduate\` | Graduate capability to generator |
|
|
239
|
+
| \`atomic trust [stack]\` | Manage trust levels |
|
|
240
|
+
| \`atomic status\` | Show system state |
|
|
241
|
+
| \`atomic history [runId]\` | Show execution history |
|
|
242
|
+
| \`atomic escalate\` | Create Beads issue for problems |
|
|
243
|
+
| \`atomic skills scan\` | Discover available skills |
|
|
244
|
+
| \`atomic skills suggest <atom>\` | Get skill recommendations |
|
|
245
|
+
| \`atomic skills assign <atom>\` | Assign skill to atom |
|
|
246
|
+
| \`atomic skills list <atom>\` | List atom's assigned skills |
|
|
247
|
+
| \`atomic skills remove <atom>\` | Remove skill from atom |
|
|
248
|
+
| \`atomic scan-generators\` | Detect existing generators |
|
|
249
|
+
| \`atomic import-generator\` | Import from Plop/Hygen/etc |
|
|
250
|
+
| \`atomic validate-generator\` | Validate imported generators |
|
|
251
|
+
|
|
252
|
+
## Best Practices
|
|
253
|
+
|
|
254
|
+
### 1. Atoms Should Be
|
|
255
|
+
|
|
256
|
+
- **Small**: Single responsibility
|
|
257
|
+
- **Idempotent**: Same input = same output (or no adverse effects)
|
|
258
|
+
- **Schema-validated**: Zod schemas for input/output
|
|
259
|
+
- **Tested**: Include test file path in definition
|
|
260
|
+
- **Descriptive**: Clear name and description
|
|
261
|
+
|
|
262
|
+
### 2. Naming Conventions
|
|
263
|
+
|
|
264
|
+
- Atom names: \`snake_case\` (e.g., \`create_component\`, \`run_migration\`)
|
|
265
|
+
- Capability names: \`snake_case\`
|
|
266
|
+
- Workflow names: \`snake_case\`
|
|
267
|
+
- Stack names: \`snake_case\`
|
|
268
|
+
|
|
269
|
+
### 3. Error Handling
|
|
270
|
+
|
|
271
|
+
Use structured errors:
|
|
272
|
+
|
|
273
|
+
\`\`\`typescript
|
|
274
|
+
import { failure, validationError, executionError } from 'atomism';
|
|
275
|
+
|
|
276
|
+
// Validation error (bad input \u2014 recoverable by default)
|
|
277
|
+
return validationError('Name cannot be empty');
|
|
278
|
+
|
|
279
|
+
// Execution error (runtime failure)
|
|
280
|
+
return executionError('Database connection failed', true /* recoverable */);
|
|
281
|
+
|
|
282
|
+
// Generic failure (full AtomError object)
|
|
283
|
+
return failure({ type: 'execution', message: 'Something went wrong', recoverable: false });
|
|
284
|
+
\`\`\`
|
|
285
|
+
|
|
286
|
+
### 4. Trust Progression
|
|
287
|
+
|
|
288
|
+
1. Start capabilities at \`new\` (human review required)
|
|
289
|
+
2. After successful executions, promote to \`proven\`
|
|
290
|
+
3. Only promote to \`trusted\` for well-tested, stable capabilities
|
|
291
|
+
4. Demote immediately if issues arise
|
|
292
|
+
|
|
293
|
+
### 5. Generator Graduation
|
|
294
|
+
|
|
295
|
+
Graduate when:
|
|
296
|
+
- Atom produces 85%+ structurally similar outputs
|
|
297
|
+
- Pattern is well-understood
|
|
298
|
+
- Template can capture the variation
|
|
299
|
+
|
|
300
|
+
Don't graduate:
|
|
301
|
+
- Spec/planning atoms (inherently variable)
|
|
302
|
+
- Creative/exploratory work
|
|
303
|
+
- Low-frequency capabilities
|
|
304
|
+
|
|
305
|
+
## Skills Assignment
|
|
306
|
+
|
|
307
|
+
Atoms can have Claude Code skills assigned to them. When an atom executes, assigned skills are loaded into Claude's context.
|
|
308
|
+
|
|
309
|
+
\`\`\`bash
|
|
310
|
+
# Scan available skills
|
|
311
|
+
atomic skills scan
|
|
312
|
+
|
|
313
|
+
# Get skill recommendations for an atom
|
|
314
|
+
atomic skills suggest my_atom
|
|
315
|
+
|
|
316
|
+
# Assign a skill to an atom
|
|
317
|
+
atomic skills assign my_atom --skill compound-engineering:workflows:review
|
|
318
|
+
|
|
319
|
+
# List skills assigned to an atom
|
|
320
|
+
atomic skills list my_atom
|
|
321
|
+
|
|
322
|
+
# Remove a skill from an atom
|
|
323
|
+
atomic skills remove my_atom --skill compound-engineering:workflows:review
|
|
324
|
+
\`\`\`
|
|
325
|
+
|
|
326
|
+
**Use skills for**:
|
|
327
|
+
- Review workflows (e.g., \`compound-engineering:review:kieran-rails-reviewer\`)
|
|
328
|
+
- Domain expertise (e.g., \`dhh-rails-style\`)
|
|
329
|
+
- Specialized capabilities the atom needs
|
|
330
|
+
|
|
331
|
+
Skills complement atoms: the skill teaches *how*, the atom enforces *what* (schema) and tracks *whether it worked* (history).
|
|
332
|
+
|
|
333
|
+
## Work Tracking with Beads
|
|
334
|
+
|
|
335
|
+
**Beads is THE work tracking system.** All atomic work that needs tracking should flow through Beads.
|
|
336
|
+
|
|
337
|
+
### Escalation
|
|
338
|
+
|
|
339
|
+
When an atom fails and you can't resolve it:
|
|
340
|
+
|
|
341
|
+
\`\`\`bash
|
|
342
|
+
# Create a Beads issue for unresolvable problems
|
|
343
|
+
atomic escalate --message "Cannot connect to database" --capability my_capability
|
|
344
|
+
|
|
345
|
+
# Link to a specific run
|
|
346
|
+
atomic escalate --run abc123 --reason "Schema validation failing on edge case"
|
|
347
|
+
|
|
348
|
+
# Include retry attempts
|
|
349
|
+
atomic escalate --capability my_atom --retries 3 --reason "Flaky network"
|
|
350
|
+
\`\`\`
|
|
351
|
+
|
|
352
|
+
### Workflow Tracking
|
|
353
|
+
|
|
354
|
+
When running workflows, atomic creates Beads issues automatically:
|
|
355
|
+
- **Parent bead**: Tracks the overall workflow
|
|
356
|
+
- **Child beads**: Track each capability execution
|
|
357
|
+
|
|
358
|
+
\`\`\`bash
|
|
359
|
+
# Workflow execution creates beads automatically
|
|
360
|
+
atomic workflow run my_workflow
|
|
361
|
+
|
|
362
|
+
# View workflow progress in Beads
|
|
363
|
+
bd list --label atomic
|
|
364
|
+
\`\`\`
|
|
365
|
+
|
|
366
|
+
## Integration with Claude Code
|
|
367
|
+
|
|
368
|
+
When working in a project with atomic:
|
|
369
|
+
|
|
370
|
+
1. **Check for \`.atomic/\`** - If present, use atomic commands
|
|
371
|
+
2. **Register new atoms** - When creating reusable tasks
|
|
372
|
+
3. **Use capabilities** - Route through registry, not direct execution
|
|
373
|
+
4. **Assign skills** - Give atoms the Claude Code skills they need
|
|
374
|
+
5. **Trust the system** - Let atomic handle validation and execution
|
|
375
|
+
6. **Escalate to Beads** - Use \`atomic escalate\` for unresolvable problems
|
|
376
|
+
7. **Suggest atomization** - When you see repetitive patterns, offer to extract
|
|
377
|
+
|
|
378
|
+
## Example: Full Workflow
|
|
379
|
+
|
|
380
|
+
\`\`\`bash
|
|
381
|
+
# 1. Initialize project
|
|
382
|
+
atomic init
|
|
383
|
+
|
|
384
|
+
# 2. Create an atom
|
|
385
|
+
cat > atoms/greet_user.ts << 'EOF'
|
|
386
|
+
import { defineAtom, success, z } from 'atomism';
|
|
387
|
+
|
|
388
|
+
export default defineAtom({
|
|
389
|
+
name: 'greet_user',
|
|
390
|
+
description: 'Generate a greeting message',
|
|
391
|
+
input: z.object({ name: z.string() }),
|
|
392
|
+
output: z.object({ greeting: z.string() }),
|
|
393
|
+
tests: { path: './greet_user.test.ts' },
|
|
394
|
+
async execute(input) {
|
|
395
|
+
return success({ greeting: \\\`Hello, \\\${input.name}!\\\` });
|
|
396
|
+
},
|
|
397
|
+
});
|
|
398
|
+
EOF
|
|
399
|
+
|
|
400
|
+
# 3. Generate tests
|
|
401
|
+
atomic test-gen atoms/greet_user.ts
|
|
402
|
+
|
|
403
|
+
# 4. Register
|
|
404
|
+
atomic register atoms/greet_user.ts --capability greet
|
|
405
|
+
|
|
406
|
+
# 5. Run
|
|
407
|
+
atomic run greet --input '{"name": "World"}'
|
|
408
|
+
|
|
409
|
+
# 6. Check status
|
|
410
|
+
atomic status
|
|
411
|
+
\`\`\`
|
|
412
|
+
|
|
413
|
+
## Troubleshooting
|
|
414
|
+
|
|
415
|
+
### "Not initialized"
|
|
416
|
+
Run \`atomic init\` in the project root.
|
|
417
|
+
|
|
418
|
+
### "Atom not found"
|
|
419
|
+
Check registration with \`atomic list\`. Register with \`atomic register <path>\`.
|
|
420
|
+
|
|
421
|
+
### "Schema validation failed"
|
|
422
|
+
Check input matches the atom's Zod schema. Use \`atomic list <atom>\` to see the expected schema.
|
|
423
|
+
|
|
424
|
+
### "Trust level insufficient"
|
|
425
|
+
Promote the stack with \`atomic trust <stack> --level proven\` or \`--level trusted\`.
|
|
426
|
+
`;
|
|
427
|
+
}
|
|
428
|
+
function getSkillPath() {
|
|
429
|
+
return join(process.cwd(), ".claude", "skills", "atomic");
|
|
430
|
+
}
|
|
431
|
+
function getSkillFilePath() {
|
|
432
|
+
return join(getSkillPath(), "SKILL.md");
|
|
433
|
+
}
|
|
434
|
+
async function skillExists() {
|
|
435
|
+
try {
|
|
436
|
+
await stat(getSkillFilePath());
|
|
437
|
+
return true;
|
|
438
|
+
} catch {
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
async function initSkill(options) {
|
|
443
|
+
const skillPath = getSkillPath();
|
|
444
|
+
const skillFile = getSkillFilePath();
|
|
445
|
+
if (!options.force && await skillExists()) {
|
|
446
|
+
return {
|
|
447
|
+
success: true,
|
|
448
|
+
path: skillFile,
|
|
449
|
+
skipped: true
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
try {
|
|
453
|
+
await mkdir(skillPath, { recursive: true });
|
|
454
|
+
const content = generateSkillContent();
|
|
455
|
+
await writeFile(skillFile, content, "utf-8");
|
|
456
|
+
return {
|
|
457
|
+
success: true,
|
|
458
|
+
path: skillFile
|
|
459
|
+
};
|
|
460
|
+
} catch (err) {
|
|
461
|
+
return {
|
|
462
|
+
success: false,
|
|
463
|
+
error: toErrorMessage(err)
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// src/commands/claude-md-init.ts
|
|
469
|
+
import { readFile, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
470
|
+
import { join as join2 } from "path";
|
|
471
|
+
var ATOMISM_MARKER = "<!-- atomism -->";
|
|
472
|
+
var ATOMISM_SECTION = `
|
|
473
|
+
${ATOMISM_MARKER}
|
|
474
|
+
## Atomism
|
|
475
|
+
|
|
476
|
+
This project uses [Atomism](https://github.com/roach88/atomism) for schema-validated, composable work units.
|
|
477
|
+
|
|
478
|
+
### Before Writing New Code
|
|
479
|
+
|
|
480
|
+
1. Check registered atoms: \`atomic list --json\`
|
|
481
|
+
2. If an atom exists for the task, use it: \`atomic run <name> --input '{}' --yes --json\`
|
|
482
|
+
3. If no atom exists but the task is repeatable, create one: \`atomic create atom <name> --json\`
|
|
483
|
+
|
|
484
|
+
### Atom API Reference
|
|
485
|
+
|
|
486
|
+
\`\`\`typescript
|
|
487
|
+
import { defineAtom, success, executionError, validationError } from 'atomism';
|
|
488
|
+
|
|
489
|
+
// Success
|
|
490
|
+
return success({ result: 'done' });
|
|
491
|
+
|
|
492
|
+
// Bad input
|
|
493
|
+
return validationError('Expected positive number');
|
|
494
|
+
|
|
495
|
+
// Runtime failure (recoverable)
|
|
496
|
+
return executionError('API timeout', true);
|
|
497
|
+
|
|
498
|
+
// Runtime failure (not recoverable)
|
|
499
|
+
return executionError('Missing required config');
|
|
500
|
+
\`\`\`
|
|
501
|
+
|
|
502
|
+
### When to Atomize
|
|
503
|
+
|
|
504
|
+
- You're about to write a standalone script for a repeatable task
|
|
505
|
+
- You notice doing the same thing 3+ times with the same shape
|
|
506
|
+
- The task has clear inputs and outputs that can be schema-validated
|
|
507
|
+
`;
|
|
508
|
+
async function initClaudeMd() {
|
|
509
|
+
const claudeDir = join2(process.cwd(), ".claude");
|
|
510
|
+
const claudeMdPath = join2(claudeDir, "CLAUDE.md");
|
|
511
|
+
if (await fileExists(claudeMdPath)) {
|
|
512
|
+
const content = await readFile(claudeMdPath, "utf-8");
|
|
513
|
+
if (content.includes(ATOMISM_MARKER)) {
|
|
514
|
+
return { success: true, path: claudeMdPath, skipped: true };
|
|
515
|
+
}
|
|
516
|
+
await writeFile2(claudeMdPath, content.trimEnd() + "\n" + ATOMISM_SECTION, "utf-8");
|
|
517
|
+
return { success: true, path: claudeMdPath };
|
|
518
|
+
}
|
|
519
|
+
await mkdir2(claudeDir, { recursive: true });
|
|
520
|
+
await writeFile2(claudeMdPath, ATOMISM_SECTION.trimStart(), "utf-8");
|
|
521
|
+
return { success: true, path: claudeMdPath };
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// src/commands/gitignore-init.ts
|
|
525
|
+
import { readFile as readFile2, writeFile as writeFile3 } from "fs/promises";
|
|
526
|
+
import { join as join3 } from "path";
|
|
527
|
+
var ATOMISM_MARKER2 = "# atomism local data";
|
|
528
|
+
var ATOMISM_ENTRIES = `
|
|
529
|
+
${ATOMISM_MARKER2}
|
|
530
|
+
.atomic/storage.db
|
|
531
|
+
.atomic/storage.db-journal
|
|
532
|
+
.atomic/runs/
|
|
533
|
+
`;
|
|
534
|
+
async function initGitignore(projectRoot) {
|
|
535
|
+
const gitignorePath = join3(projectRoot, ".gitignore");
|
|
536
|
+
if (await fileExists(gitignorePath)) {
|
|
537
|
+
const content = await readFile2(gitignorePath, "utf-8");
|
|
538
|
+
if (content.includes(ATOMISM_MARKER2)) {
|
|
539
|
+
return { success: true, path: gitignorePath, skipped: true };
|
|
540
|
+
}
|
|
541
|
+
await writeFile3(gitignorePath, content.trimEnd() + "\n" + ATOMISM_ENTRIES, "utf-8");
|
|
542
|
+
return { success: true, path: gitignorePath };
|
|
543
|
+
}
|
|
544
|
+
await writeFile3(gitignorePath, ATOMISM_ENTRIES.trimStart(), "utf-8");
|
|
545
|
+
return { success: true, path: gitignorePath };
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// src/commands/init.ts
|
|
549
|
+
async function ensureDeps(projectRoot) {
|
|
550
|
+
const pkgPath = join4(projectRoot, "package.json");
|
|
551
|
+
const tsconfigPath = join4(projectRoot, "tsconfig.json");
|
|
552
|
+
let packageJsonCreated = false;
|
|
553
|
+
let tsconfigCreated = false;
|
|
554
|
+
let atomismLinked = false;
|
|
555
|
+
let hasPackageJson = false;
|
|
556
|
+
try {
|
|
557
|
+
await access(pkgPath);
|
|
558
|
+
hasPackageJson = true;
|
|
559
|
+
} catch {
|
|
560
|
+
}
|
|
561
|
+
if (!hasPackageJson) {
|
|
562
|
+
const minimal = {
|
|
563
|
+
private: true,
|
|
564
|
+
description: "Atomism-enabled project",
|
|
565
|
+
dependencies: {}
|
|
566
|
+
};
|
|
567
|
+
await writeFile4(pkgPath, JSON.stringify(minimal, null, 2) + "\n");
|
|
568
|
+
packageJsonCreated = true;
|
|
569
|
+
}
|
|
570
|
+
let hasTsconfig = false;
|
|
571
|
+
try {
|
|
572
|
+
await access(tsconfigPath);
|
|
573
|
+
hasTsconfig = true;
|
|
574
|
+
} catch {
|
|
575
|
+
}
|
|
576
|
+
let tsconfigNeedsInclude;
|
|
577
|
+
let suggestedInclude;
|
|
578
|
+
if (hasTsconfig) {
|
|
579
|
+
try {
|
|
580
|
+
const raw = await readFile3(tsconfigPath, "utf-8");
|
|
581
|
+
const parsed = JSON.parse(raw);
|
|
582
|
+
const includes = Array.isArray(parsed.include) ? parsed.include : [];
|
|
583
|
+
const coversAtoms = includes.some(
|
|
584
|
+
(pattern) => pattern === "atoms/**/*.ts" || pattern.startsWith("atoms/") || pattern === "**/*.ts" || pattern === "./**/*.ts"
|
|
585
|
+
);
|
|
586
|
+
if (!coversAtoms) {
|
|
587
|
+
tsconfigNeedsInclude = true;
|
|
588
|
+
suggestedInclude = "atoms/**/*.ts";
|
|
589
|
+
}
|
|
590
|
+
} catch {
|
|
591
|
+
}
|
|
592
|
+
} else {
|
|
593
|
+
const tsconfig = {
|
|
594
|
+
compilerOptions: {
|
|
595
|
+
target: "ES2022",
|
|
596
|
+
module: "ESNext",
|
|
597
|
+
moduleResolution: "bundler",
|
|
598
|
+
strict: true,
|
|
599
|
+
esModuleInterop: true,
|
|
600
|
+
skipLibCheck: true,
|
|
601
|
+
outDir: "dist"
|
|
602
|
+
},
|
|
603
|
+
include: ["atoms/**/*.ts"]
|
|
604
|
+
};
|
|
605
|
+
await writeFile4(tsconfigPath, JSON.stringify(tsconfig, null, 2) + "\n");
|
|
606
|
+
tsconfigCreated = true;
|
|
607
|
+
}
|
|
608
|
+
try {
|
|
609
|
+
execSync(`node -e "require.resolve('atomism')"`, {
|
|
610
|
+
cwd: projectRoot,
|
|
611
|
+
stdio: "ignore"
|
|
612
|
+
});
|
|
613
|
+
return { success: true, packageJsonCreated, tsconfigCreated, tsconfigNeedsInclude, suggestedInclude, atomismLinked };
|
|
614
|
+
} catch {
|
|
615
|
+
}
|
|
616
|
+
try {
|
|
617
|
+
execSync("npm link atomism", {
|
|
618
|
+
cwd: projectRoot,
|
|
619
|
+
stdio: "ignore",
|
|
620
|
+
timeout: 3e4
|
|
621
|
+
});
|
|
622
|
+
atomismLinked = true;
|
|
623
|
+
} catch {
|
|
624
|
+
return {
|
|
625
|
+
success: false,
|
|
626
|
+
packageJsonCreated,
|
|
627
|
+
tsconfigCreated,
|
|
628
|
+
tsconfigNeedsInclude,
|
|
629
|
+
suggestedInclude,
|
|
630
|
+
atomismLinked: false,
|
|
631
|
+
error: "Could not resolve atomism. Run: npm link atomism (if globally installed) or npm install atomism"
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
return { success: true, packageJsonCreated, tsconfigCreated, tsconfigNeedsInclude, suggestedInclude, atomismLinked };
|
|
635
|
+
}
|
|
636
|
+
async function initCommand(options) {
|
|
637
|
+
await withErrorHandling(options, async () => {
|
|
638
|
+
const projectRoot = process.cwd();
|
|
639
|
+
const result = await initStorage(projectRoot);
|
|
640
|
+
let depsResult;
|
|
641
|
+
try {
|
|
642
|
+
depsResult = await ensureDeps(projectRoot);
|
|
643
|
+
} catch (depsError) {
|
|
644
|
+
depsResult = {
|
|
645
|
+
success: false,
|
|
646
|
+
packageJsonCreated: false,
|
|
647
|
+
tsconfigCreated: false,
|
|
648
|
+
atomismLinked: false,
|
|
649
|
+
error: toErrorMessage(depsError)
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
let skillResult;
|
|
653
|
+
try {
|
|
654
|
+
skillResult = await initSkill({ force: false });
|
|
655
|
+
} catch (skillError) {
|
|
656
|
+
skillResult = {
|
|
657
|
+
success: false,
|
|
658
|
+
error: toErrorMessage(skillError)
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
let claudeMdResult;
|
|
662
|
+
try {
|
|
663
|
+
claudeMdResult = await initClaudeMd();
|
|
664
|
+
} catch (claudeError) {
|
|
665
|
+
claudeMdResult = {
|
|
666
|
+
success: false,
|
|
667
|
+
error: toErrorMessage(claudeError)
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
let gitignoreResult;
|
|
671
|
+
try {
|
|
672
|
+
gitignoreResult = await initGitignore(projectRoot);
|
|
673
|
+
} catch (gitignoreError) {
|
|
674
|
+
gitignoreResult = {
|
|
675
|
+
success: false,
|
|
676
|
+
error: toErrorMessage(gitignoreError)
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
if (options.json) {
|
|
680
|
+
console.log(JSON.stringify({
|
|
681
|
+
...result,
|
|
682
|
+
deps: depsResult,
|
|
683
|
+
skill: skillResult,
|
|
684
|
+
claudeMd: claudeMdResult,
|
|
685
|
+
gitignore: gitignoreResult
|
|
686
|
+
}, null, 2));
|
|
687
|
+
} else {
|
|
688
|
+
if (result.created) {
|
|
689
|
+
console.log(`\u2713 Created ${result.path}`);
|
|
690
|
+
} else {
|
|
691
|
+
console.log(`\u2713 ${result.path} already exists`);
|
|
692
|
+
}
|
|
693
|
+
console.log(`\u2713 Database initialized at ${result.dbPath}`);
|
|
694
|
+
console.log(`\u2713 ${result.migrationsRun} migrations applied`);
|
|
695
|
+
if (depsResult.success) {
|
|
696
|
+
if (depsResult.packageJsonCreated) {
|
|
697
|
+
console.log("\u2713 Created package.json for module resolution");
|
|
698
|
+
}
|
|
699
|
+
if (depsResult.tsconfigCreated) {
|
|
700
|
+
console.log("\u2713 Created tsconfig.json for atom type inference");
|
|
701
|
+
}
|
|
702
|
+
if (depsResult.atomismLinked) {
|
|
703
|
+
console.log("\u2713 Linked atomism for module resolution");
|
|
704
|
+
}
|
|
705
|
+
} else {
|
|
706
|
+
console.log(`\u26A0 Module resolution: ${depsResult.error ?? "unknown error"}`);
|
|
707
|
+
}
|
|
708
|
+
if (depsResult.tsconfigNeedsInclude) {
|
|
709
|
+
console.log(`\u26A0 tsconfig.json does not include atom files. Add to your "include" array:`);
|
|
710
|
+
console.log(` "${depsResult.suggestedInclude}"`);
|
|
711
|
+
}
|
|
712
|
+
if (skillResult.success && !skillResult.skipped) {
|
|
713
|
+
console.log(`\u2713 Claude Code skill created at ${skillResult.path}`);
|
|
714
|
+
} else if (skillResult.skipped) {
|
|
715
|
+
console.log("\u2713 Claude Code skill already exists");
|
|
716
|
+
} else if (!skillResult.success) {
|
|
717
|
+
console.log(`\u26A0 Claude Code skill creation failed: ${skillResult.error ?? "unknown error"}`);
|
|
718
|
+
}
|
|
719
|
+
if (claudeMdResult.success && !claudeMdResult.skipped) {
|
|
720
|
+
console.log(`\u2713 CLAUDE.md updated at ${claudeMdResult.path}`);
|
|
721
|
+
} else if (claudeMdResult.skipped) {
|
|
722
|
+
console.log("\u2713 CLAUDE.md already has atomism section");
|
|
723
|
+
} else if (!claudeMdResult.success) {
|
|
724
|
+
console.log(`\u26A0 CLAUDE.md update failed: ${claudeMdResult.error ?? "unknown error"}`);
|
|
725
|
+
}
|
|
726
|
+
if (gitignoreResult.success && !gitignoreResult.skipped) {
|
|
727
|
+
console.log(`\u2713 .gitignore updated at ${gitignoreResult.path}`);
|
|
728
|
+
} else if (gitignoreResult.skipped) {
|
|
729
|
+
console.log("\u2713 .gitignore already has atomism entries");
|
|
730
|
+
} else if (!gitignoreResult.success) {
|
|
731
|
+
console.log(`\u26A0 .gitignore update failed: ${gitignoreResult.error ?? "unknown error"}`);
|
|
732
|
+
}
|
|
733
|
+
console.log("\nReady to register atoms with: atomic register <path>");
|
|
734
|
+
console.log("Commit: registry.json, trust.json, atoms/");
|
|
735
|
+
}
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
export {
|
|
739
|
+
initCommand
|
|
740
|
+
};
|
|
741
|
+
//# sourceMappingURL=init-2FINDMYK.js.map
|