@amalgm/agents 0.2.0 → 0.2.2

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/PURPOSE.md CHANGED
@@ -27,6 +27,9 @@ hosts supply explicit ports for resources owned by other products.
27
27
 
28
28
  ## Axioms
29
29
 
30
+ Managed releases bind to one exact published Core version and build from the
31
+ locked dependency graph on the supported Node toolchain.
32
+
30
33
  1. A user can create, list, inspect, edit, and delete agents.
31
34
  2. A user or another agent can resolve an available agent to one exact
32
35
  immutable revision without starting a conversation.
package/README.md CHANGED
@@ -115,7 +115,8 @@ The CLI reads the same SQLite registry as the SDK.
115
115
  - [MCP server](./docs/MCP.md)
116
116
  - [Persistence](./docs/DATA_MODEL.md)
117
117
  - [Security model](./docs/SECURITY.md)
118
- - [Engine integration](./docs/ENGINE_INTEGRATION.md)
118
+ - [Shell integration](./docs/SHELL_INTEGRATION.md)
119
+ - [Historical Engine integration](./docs/ENGINE_INTEGRATION.md)
119
120
 
120
121
  ## Development
121
122
 
@@ -1,29 +1,12 @@
1
- # Shell integration
1
+ # Historical Engine integration
2
2
 
3
- Shell is the composition root. Agents supplies the canonical registry and Chat
4
- supplies the canonical conversation runtime.
3
+ Amalgm Engine is deprecated. Its former agent registry, configuration, talk,
4
+ REST, and MCP implementations are reference evidence for migrations and
5
+ parity only. They are not active execution or persistence authorities and are
6
+ never a fallback beside Shell.
5
7
 
6
- ## Resolver boundary
8
+ Agents now owns identities, installations, immutable revisions, and portable
9
+ bundles. Chat owns conversations and turns. Shell resolves exact Agents
10
+ revisions into prepared Chat executions through the public packages.
7
11
 
8
- Shell gives Chat a resolver with one job: map an installed agent id and optional
9
- revision id to `agents.getAgentRevision(agentId, revisionId)`, then project that
10
- immutable definition into Chat's execution contract. The resolver never writes
11
- either product's store.
12
-
13
- Chat owns the conversation, accepted prompt, provider session, ordered durable
14
- updates, transcript, usage, reconnect, and interrupt lifecycle. Agents owns the
15
- identity and revision selected by that execution. Neither product imports the
16
- other's database.
17
-
18
- Tool and action ids are resolved through `@amalgm/tools`; `authRef` is resolved
19
- through the credential boundary. The resulting concrete values are frozen by
20
- Chat before it accepts a turn.
21
-
22
- ## Integration checks
23
-
24
- - create, update, list, delete, and exact revision resolution use `Agents`;
25
- - editing an agent never changes a Chat execution that already names a revision;
26
- - Toolbox and credential references are authorized during preparation;
27
- - provider restart, reconnect, and interrupt are handled only by Chat; and
28
- - agent-to-agent interaction creates or joins a Chat conversation through the
29
- same prepared-execution protocol as the UI.
12
+ See [SHELL_INTEGRATION.md](./SHELL_INTEGRATION.md) for the active boundary.
@@ -0,0 +1,29 @@
1
+ # Shell integration
2
+
3
+ Shell is the composition root. Agents supplies the canonical registry and Chat
4
+ supplies the canonical conversation runtime.
5
+
6
+ ## Resolver boundary
7
+
8
+ Shell gives Chat a resolver with one job: map an installed agent id and optional
9
+ revision id to `agents.getAgentRevision(agentId, revisionId)`, then project that
10
+ immutable definition into Chat's execution contract. The resolver never writes
11
+ either product's store.
12
+
13
+ Chat owns the conversation, accepted prompt, provider session, ordered durable
14
+ updates, transcript, usage, reconnect, and interrupt lifecycle. Agents owns the
15
+ identity and revision selected by that execution. Neither product imports the
16
+ other's database.
17
+
18
+ Tool and action ids are resolved through `@amalgm/tools`; `authRef` is resolved
19
+ through the credential boundary. The resulting concrete values are frozen by
20
+ Chat before it accepts a turn.
21
+
22
+ ## Integration checks
23
+
24
+ - create, update, list, delete, and exact revision resolution use `Agents`;
25
+ - editing an agent never changes a Chat execution that already names a revision;
26
+ - Toolbox and credential references are authorized during preparation;
27
+ - provider restart, reconnect, and interrupt are handled only by Chat; and
28
+ - agent-to-agent interaction creates or joins a Chat conversation through the
29
+ same prepared-execution protocol as the UI.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amalgm/agents",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Local-first agent identities, installations, and immutable revisions.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -42,17 +42,17 @@
42
42
  "README.md"
43
43
  ],
44
44
  "scripts": {
45
- "build": "rm -rf dist && tsc -p tsconfig.build.json && tsx scripts/mark-executables.ts",
45
+ "build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json && tsx scripts/mark-executables.ts",
46
46
  "check": "tsx scripts/check-tree.ts && tsc -p tsconfig.json && tsc -p tsconfig.test.json",
47
47
  "test": "tsx --test --test-concurrency=1 --test-timeout=30000 test/*.test.ts",
48
48
  "verify": "npm run check && npm run build && npm test",
49
49
  "prepack": "npm run build"
50
50
  },
51
51
  "engines": {
52
- "node": ">=20"
52
+ "node": ">=24"
53
53
  },
54
54
  "dependencies": {
55
- "@amalgm/core": "^0.1.0",
55
+ "@amalgm/core": "0.4.7",
56
56
  "@types/better-sqlite3": "^7.6.13",
57
57
  "@types/node": "^20.19.43",
58
58
  "better-sqlite3": "^12.6.2"
@@ -1,21 +1,241 @@
1
1
  ---
2
2
  name: amalgm-agents
3
- description: Create, inspect, edit, delete, install, and resolve persistent Amalgm agent identities and immutable revisions. Use when a user wants to manage an agent definition or discover available agents.
3
+ description: Manage persistent Amalgm agent identities and their immutable revisions with the @amalgm/agents SDK, CLI, REST API, or MCP tools. Use when you need to define an agent (its harness, model, instructions, tools, skills, and workspace), list or inspect existing agents, edit or delete one, or resolve the exact revision to run through Chat.
4
4
  ---
5
5
 
6
- # Amalgm Agents
6
+ # Agents
7
7
 
8
- Use the available Agents MCP tools. If MCP is unavailable, use the equivalent
9
- `amalgm-agents` CLI command.
8
+ Agents is the registry for durable agent definitions on the Amalgm platform. It stores three things: **identities** (a stable id like `reviewer` that survives renames and edits), **installations** (the agent identities available on the local machine), and **immutable revisions** (append-only snapshots of every definition an identity has ever had). You define an agent once — its harness, model, instructions, tools, skills, and workspace — and every surface on the machine (SDK, CLI, REST, MCP, and the Amalgm apps) reads and writes the same local SQLite registry. Agents does not run conversations: it resolves an exact revision, and Chat executes it.
10
9
 
11
- ## Manage agents
10
+ ## Installation
12
11
 
13
- 1. List or inspect before changing an existing agent.
14
- 2. Create from a complete definition.
15
- 3. Update only the fields the user requested.
16
- 4. Delete only when the user explicitly asks.
17
- 5. Keep tool, skill, file, credential, and subagent values as references; do
18
- not copy those products into the agent definition.
12
+ Install the package from npm. It requires Node 20 or later.
19
13
 
20
- To run an agent, resolve its identity here and use Chat. Agents has no
21
- conversation, execution, transcript, interrupt, or reconnect operation.
14
+ ```bash
15
+ npm install @amalgm/agents
16
+ ```
17
+
18
+ The install also provides three executables: `amalgm-agents` (CLI), `amalgm-agents-mcp` (stdio MCP server), and `amalgm-agents-rest` (loopback REST server). Run them with `npx` or add the package's `.bin` directory to your `PATH`.
19
+
20
+ ```bash
21
+ npx amalgm-agents --help
22
+ ```
23
+
24
+ ## Quickstart
25
+
26
+ Create an agent, list what exists, and resolve the revision you would hand to Chat. The `Agents` class is synchronous and local-first — every mutation is written to disk before the call returns.
27
+
28
+ ```ts
29
+ import { Agents } from '@amalgm/agents';
30
+
31
+ const agents = new Agents({ stateDir: './state' });
32
+
33
+ try {
34
+ // Define and create an agent. `id`, `name`, and `driver` are required;
35
+ // everything else has a sensible empty default.
36
+ agents.createAgent({
37
+ id: 'reviewer',
38
+ name: 'Reviewer',
39
+ description: 'Reviews implementation work',
40
+ driver: 'codex',
41
+ instructions: 'Find correctness risks before style issues.',
42
+ });
43
+
44
+ // List every available (non-deleted) agent.
45
+ for (const agent of agents.listAgents()) {
46
+ console.log(agent.id, agent.definition.name, `rev ${agent.currentRevision}`);
47
+ }
48
+
49
+ // Inspect one agent's current definition.
50
+ const record = agents.getAgent('reviewer');
51
+ console.log(record?.definition.instructions);
52
+
53
+ // Resolve the exact immutable revision a host such as Chat would execute.
54
+ const revision = agents.getAgentRevision('reviewer');
55
+ console.log(revision.id, revision.number, revision.hash);
56
+ } finally {
57
+ agents.close();
58
+ }
59
+ ```
60
+
61
+ By default the registry lives at `~/.amalgm/users/local/agents/agents.db`. Pass `stateDir` to keep state somewhere else (useful for tests and embedded hosts), or `databasePath` to point at a database file directly. Setting the `AMALGAM_AGENTS_DIR` environment variable overrides the default location without code changes.
62
+
63
+ ## Core concepts
64
+
65
+ Agents separates three ideas that most agent frameworks blur together. Keeping them distinct is what makes agent executions reproducible.
66
+
67
+ ### Identity
68
+
69
+ An identity is the stable machine name of an agent: 1–128 lowercase letters, numbers, dots, underscores, or hyphens. Renaming the human-readable `name` never changes the `id`, and other products reference agents by this id. Deleting an agent tombstones the identity rather than erasing it — the id stays reserved so that recorded history can never silently point at a different, later agent.
70
+
71
+ ### Revision
72
+
73
+ Every content change to a definition appends an immutable revision: a numbered, hashed snapshot of the complete normalized definition. Revisions are immutable for one reason — Chat records the exact revision used by each execution, so a conversation transcript always names precisely the instructions, model, and tool references that produced it. Editing an agent today can never rewrite what an execution meant yesterday.
74
+
75
+ Two consequences follow from the append-only design:
76
+
77
+ - **Idempotent edits.** Submitting a patch that produces identical content keeps the current revision; nothing is appended.
78
+ - **No revision reuse.** Reverting to content an earlier revision had still creates a *new* revision number, so the timeline of what the definition was, and when, stays complete.
79
+
80
+ ### Installation
81
+
82
+ An installation is one agent identity available on the local machine, together with its home descriptor. The registry is per-machine and local-first: `listAgents()` answers "which agents can this machine run right now". Portable bundles let you move an agent (with its subagent, skill, and tool graph) between machines; installing a bundle creates fresh local identities rather than overwriting existing ones.
83
+
84
+ ## Agent definitions
85
+
86
+ A definition is complete, portable execution configuration. It holds *references* to things owned by other products — tools, skills, files, credentials, subagents — never copies of them and never secrets.
87
+
88
+ ```json
89
+ {
90
+ "id": "reviewer",
91
+ "name": "Reviewer",
92
+ "description": "Reviews implementation work",
93
+ "instructions": "Find correctness risks before style issues.",
94
+ "driver": { "id": "codex", "config": { "sandbox": "workspace-write" } },
95
+ "model": { "id": "openai/gpt-5.5", "settings": { "effort": "high" } },
96
+ "authRef": "openai-primary",
97
+ "resources": {
98
+ "files": ["AGENTS.md"],
99
+ "skills": ["code-review"],
100
+ "subagents": ["security-reviewer"]
101
+ },
102
+ "toolbox": {
103
+ "toolIds": ["git"],
104
+ "actionIds": ["github.pull_request_get"]
105
+ },
106
+ "workspace": { "cwd": "/projects/product" },
107
+ "metadata": { "icon": "search" }
108
+ }
109
+ ```
110
+
111
+ Field notes:
112
+
113
+ - `driver` names the harness that will run the agent. As shorthand you may pass a plain string (`"driver": "codex"` becomes `{ "id": "codex", "config": {} }`). `driver.config` is non-secret harness configuration interpreted at execution time.
114
+ - `model` and `authRef` are nullable. `authRef` names a credential that the host resolves when the agent runs; the secret itself never enters the definition.
115
+ - `resources` and `toolbox` are lists of opaque ids resolved by the host. Arrays are de-duplicated and order-normalized.
116
+ - `metadata` is free-form JSON for your own annotations (icons, tags, owners).
117
+
118
+ ## SDK reference
119
+
120
+ `Agents` is the single behavior boundary — the CLI, REST, and MCP surfaces are thin adapters over these same methods, so behavior is identical everywhere.
121
+
122
+ | Method | Behavior |
123
+ |---|---|
124
+ | `createAgent(definition)` | Create an identity and immutable revision 1 |
125
+ | `updateAgent(id, patch)` | Merge a patch; append a revision only when content changes |
126
+ | `deleteAgent(id)` | Tombstone the identity, retaining all revisions |
127
+ | `getAgent(id, includeDeleted?)` | Read the current record, or `null` if absent |
128
+ | `listAgents(includeDeleted?)` | List available agents (tombstones excluded by default) |
129
+ | `getAgentRevision(agentId, revisionId?)` | Resolve the current or one exact immutable revision |
130
+ | `health()` | Liveness summary for the open registry |
131
+ | `close()` | Release the underlying database |
132
+
133
+ ### Patching
134
+
135
+ Patches are partial definitions with predictable merge rules: top-level fields replace their prior values, while the known nested objects — `driver`, `resources`, `toolbox`, and `workspace` — merge field by field. That means a patch touching only `resources.skills` preserves `resources.files` and `resources.subagents`. Set a nullable field to `null` to clear it.
136
+
137
+ ```ts
138
+ const updated = agents.updateAgent('reviewer', {
139
+ instructions: 'Review for correctness first, style second.',
140
+ resources: { skills: ['code-review', 'security-review'] },
141
+ model: null, // clear the pinned model; the host default applies
142
+ });
143
+ console.log(updated.currentRevision); // bumped, because content changed
144
+ ```
145
+
146
+ ### Errors
147
+
148
+ Expected failures throw `AgentError` with a stable `code` — `invalid_input`, `not_found`, `conflict`, `deleted`, or `too_large` — plus a matching HTTP `status` used by the REST surface. Catch and branch on the code rather than the message.
149
+
150
+ ```ts
151
+ import { Agents, AgentError } from '@amalgm/agents';
152
+
153
+ try {
154
+ agents.updateAgent('missing-id', { name: 'Nope' });
155
+ } catch (error) {
156
+ if (error instanceof AgentError && error.code === 'not_found') {
157
+ console.log('No such agent.');
158
+ } else {
159
+ throw error;
160
+ }
161
+ }
162
+ ```
163
+
164
+ ## CLI
165
+
166
+ The `amalgm-agents` CLI shares the SDK database — there is no separate CLI registry. It prints JSON to stdout and errors to stderr, so it composes cleanly with `jq` and scripts.
167
+
168
+ ```bash
169
+ amalgm-agents agent list [--include-deleted]
170
+ amalgm-agents agent show <id> [--include-deleted]
171
+ amalgm-agents agent create <definition.json>
172
+ amalgm-agents agent update <id> <patch.json>
173
+ amalgm-agents agent delete <id>
174
+ ```
175
+
176
+ `create` and `update` read a JSON file — a complete definition and a partial patch respectively, using exactly the shapes shown above. Global options are `--state-dir <path>` (choose the registry location) and `--help`.
177
+
178
+ ```bash
179
+ # Create from a file, then confirm the revision advanced after an edit.
180
+ amalgm-agents agent create reviewer.json
181
+ echo '{"instructions": "Be terse."}' > patch.json
182
+ amalgm-agents agent update reviewer patch.json
183
+ amalgm-agents agent show reviewer | jq .currentRevision
184
+ ```
185
+
186
+ ## REST API
187
+
188
+ For non-Node hosts, run the loopback REST server or embed it with `createRestServer` from `@amalgm/agents/http`.
189
+
190
+ ```bash
191
+ amalgm-agents-rest --host 127.0.0.1 --port 4317 --token "$TOKEN"
192
+ ```
193
+
194
+ When a token is configured, authenticate with `Authorization: Bearer <token>`; `/healthz` stays unauthenticated. JSON bodies are limited to 512 KB by default.
195
+
196
+ | Method | Path | Result |
197
+ |---|---|---|
198
+ | `GET` | `/v1/agents` | List available agents |
199
+ | `POST` | `/v1/agents` | Create from a complete definition |
200
+ | `GET` | `/v1/agents/:id` | Read the current definition |
201
+ | `PATCH` | `/v1/agents/:id` | Apply a definition patch |
202
+ | `DELETE` | `/v1/agents/:id` | Tombstone an identity |
203
+
204
+ Add `?include_deleted=true` to list or get requests to include tombstones. There are no conversation routes — execution belongs to Chat.
205
+
206
+ ## MCP tools
207
+
208
+ `amalgm-agents-mcp` runs the registry as a stdio MCP server, so any MCP-capable assistant can manage agents. `createMcpServer` from `@amalgm/agents/mcp` embeds the same server in your own host.
209
+
210
+ ```bash
211
+ amalgm-agents-mcp --state-dir ./state
212
+ ```
213
+
214
+ It exposes five tools, each a direct projection of an SDK method:
215
+
216
+ | Tool | Arguments | Behavior |
217
+ |---|---|---|
218
+ | `agents_list` | `include_deleted?` | List persistent agent definitions |
219
+ | `agents_get` | `agent_id`, `include_deleted?` | Read one agent and its current revision |
220
+ | `agents_create` | `definition` | Create from a complete definition |
221
+ | `agents_update` | `agent_id`, `patch` | Patch; content changes append a revision |
222
+ | `agents_delete` | `agent_id` | Tombstone an identity, retaining revisions |
223
+
224
+ When working through these tools, list or inspect before changing an existing agent, patch only the fields being changed, and keep tool, skill, file, credential, and subagent values as references rather than inlining their content.
225
+
226
+ ## Running agents with Chat
227
+
228
+ Agents deliberately contains no conversation, execution, transcript, interrupt, or reconnect operation. To run an agent, resolve its identity here and hand the result to Chat:
229
+
230
+ 1. Select an installed agent identity (from `listAgents` or a known id).
231
+ 2. Call `getAgentRevision(agentId, revisionId?)` — you get the current revision, or one exact historical revision if you pass its id.
232
+ 3. Project that immutable definition into Chat's execution contract. Chat resolves the `toolbox`, `resources`, and `authRef` references into concrete values, freezes them, and then accepts the turn.
233
+ 4. Chat records which revision it executed, so the conversation remains reproducible even after the agent is edited or deleted.
234
+
235
+ ```ts
236
+ const revision = agents.getAgentRevision('reviewer');
237
+ // revision.definition is the frozen, normalized definition:
238
+ // pass it to Chat to start or continue a conversation as this agent.
239
+ ```
240
+
241
+ The division of labor is strict by design: Agents answers "what is this agent, exactly?", and Chat owns everything about running it — the conversation, turns, streams, usage, interrupts, and reconnects. Editing an agent never changes a Chat execution that already names a revision.