antpath 0.3.1 → 0.4.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.
- package/README.md +13 -14
- package/dist/_shared/blueprint.d.ts +263 -0
- package/dist/_shared/blueprint.js +505 -0
- package/dist/_shared/http.d.ts +6 -1
- package/dist/_shared/http.js +10 -5
- package/dist/_shared/index.d.ts +1 -0
- package/dist/_shared/index.js +1 -0
- package/dist/_shared/operations.d.ts +32 -9
- package/dist/_shared/operations.js +73 -12
- package/dist/_shared/runtime-types.d.ts +30 -0
- package/dist/_shared/stable.d.ts +14 -0
- package/dist/_shared/stable.js +14 -0
- package/dist/_shared/submission.d.ts +55 -0
- package/dist/_shared/submission.js +135 -1
- package/dist/cli.mjs +114 -58
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +13 -6
- package/dist/client.js +17 -16
- package/dist/client.js.map +1 -1
- package/docs/credentials.md +1 -3
- package/docs/quickstart.md +4 -7
- package/docs/release.md +57 -12
- package/examples/mcp-static-bearer.ts +1 -3
- package/examples/quickstart.ts +1 -3
- package/package.json +2 -3
- package/references/architecture-decisions.md +0 -473
- package/references/implementation-plan.md +0 -452
- package/references/research-sources.md +0 -41
- package/references/testing-strategy.md +0 -29
package/README.md
CHANGED
|
@@ -16,24 +16,26 @@ import {
|
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
antpath run ./template.json --api-token ant_…
|
|
19
|
+
antpath run ./template.json --api-token ant_… \
|
|
20
20
|
--anthropic-api-key sk-ant-… --follow
|
|
21
|
-
antpath status <run-id> --api-token …
|
|
22
|
-
antpath events <run-id> --api-token … --
|
|
23
|
-
antpath outputs <run-id> --api-token …
|
|
24
|
-
antpath download <run-id> <output-id> --out ./local --api-token …
|
|
25
|
-
antpath cancel <run-id> --api-token …
|
|
26
|
-
antpath delete <run-id> --api-token …
|
|
27
|
-
antpath whoami --api-token …
|
|
21
|
+
antpath status <run-id> --api-token …
|
|
22
|
+
antpath events <run-id> --api-token … --follow
|
|
23
|
+
antpath outputs <run-id> --api-token …
|
|
24
|
+
antpath download <run-id> <output-id> --out ./local --api-token …
|
|
25
|
+
antpath cancel <run-id> --api-token …
|
|
26
|
+
antpath delete <run-id> --api-token …
|
|
27
|
+
antpath whoami --api-token …
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
The SDK class and the CLI are backed by the same `@antpath/shared` operations module — any read or write you can do through one, you can do through the other, against the same durable run records. The same npm package also ships the in-container `antpath` CLI as its `bin` entry; the worker mounts that CLI at `/antpath/antpath` inside every run so skills can call `antpath proxy …` against the per-run manifest. See [Agent-first surface design](../../references/development-principles.md#agent-first-surface-design).
|
|
31
31
|
|
|
32
|
+
The dashboard URL defaults to `https://antpath.ai`. Self-hosted deployments override with `--dashboard-url` on the CLI or `baseUrl` on `AntpathClient`. The workspace is derived server-side from your API token (1:1 binding), so there is no `--workspace` flag and no `workspaceId` option.
|
|
33
|
+
|
|
32
34
|
## MVP boundaries
|
|
33
35
|
|
|
34
36
|
- Claude Managed Agents only.
|
|
35
37
|
- BYO Anthropic key + MCP credentials + skill references — passed inline on every submission, vaulted for the lifetime of a single run, destroyed at cleanup.
|
|
36
|
-
- Workspace is the tenant boundary.
|
|
38
|
+
- Workspace is the tenant boundary. Workspace identity is derived server-side from the API token (1:1 binding); the SDK / CLI never name it.
|
|
37
39
|
- No SDK-side storage of provider keys, MCP credentials, or output file contents.
|
|
38
40
|
- Cleanup runs by default; opt into retention with `cleanup.session: "retain"`.
|
|
39
41
|
|
|
@@ -43,9 +45,8 @@ The SDK class and the CLI are backed by the same `@antpath/shared` operations mo
|
|
|
43
45
|
import { AntpathClient, defineTemplate, string } from "antpath";
|
|
44
46
|
|
|
45
47
|
const client = new AntpathClient({
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
workspaceId: process.env.ANTPATH_WORKSPACE_ID!
|
|
48
|
+
apiToken: process.env.ANTPATH_API_TOKEN!
|
|
49
|
+
// baseUrl defaults to https://antpath.ai — set it for self-hosted deployments.
|
|
49
50
|
});
|
|
50
51
|
|
|
51
52
|
const template = defineTemplate({
|
|
@@ -84,8 +85,6 @@ The same flow from the CLI:
|
|
|
84
85
|
```bash
|
|
85
86
|
antpath run ./template.json \
|
|
86
87
|
--api-token "$ANTPATH_API_TOKEN" \
|
|
87
|
-
--workspace "$ANTPATH_WORKSPACE_ID" \
|
|
88
|
-
--dashboard-url https://antpath.example.com \
|
|
89
88
|
--anthropic-api-key "$ANTHROPIC_API_KEY" \
|
|
90
89
|
--var topic="agent-first SDK design" \
|
|
91
90
|
--follow
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The flat agent-first composition surface that replaces `Template`.
|
|
3
|
+
*
|
|
4
|
+
* Concepts (mirrored in references/architecture-decisions.md):
|
|
5
|
+
*
|
|
6
|
+
* - `SkillRef` is the wire-level reference to a skill — either an
|
|
7
|
+
* `skl_*` id pointing at a workspace-uploaded bundle, or a
|
|
8
|
+
* `{vendor, skillId, version}` reference to a provider built-in.
|
|
9
|
+
* The two shapes are discriminated by `kind` so consumers branch
|
|
10
|
+
* mechanically and providers can never accidentally be looked up
|
|
11
|
+
* in `skill_bundles`.
|
|
12
|
+
*
|
|
13
|
+
* - `McpServerRef` is the non-secret part of an MCP server declaration:
|
|
14
|
+
* `name` and `url`. Bearer / cookie / per-request headers travel in
|
|
15
|
+
* the run's vaulted `secrets.mcpServers` block keyed by the same
|
|
16
|
+
* `name`, and never enter the hashed submission payload or the
|
|
17
|
+
* run snapshot.
|
|
18
|
+
*
|
|
19
|
+
* - `Blueprint` is what the user authors. It excludes
|
|
20
|
+
* `secrets`/`idempotencyKey`/`signal` so it can be safely persisted
|
|
21
|
+
* to disk (e.g. `antpath run --config run.json`), shared between
|
|
22
|
+
* teams, or curried via `defineRun` without leaking credentials.
|
|
23
|
+
* Strings inside a Blueprint are **already resolved** — there are
|
|
24
|
+
* no `{{variable}}` placeholders, no template language, no late
|
|
25
|
+
* binding. The whole point of `defineRun` is to make the resolution
|
|
26
|
+
* happen at the TS call site where the IDE can type-check it.
|
|
27
|
+
*
|
|
28
|
+
* - Skill bundle validation lives here so the SDK (zipping locally),
|
|
29
|
+
* the BFF (server-side unzip + manifest extraction), and the worker
|
|
30
|
+
* (sanity-check before mounting) share a single source of truth for
|
|
31
|
+
* the limits, the path normaliser, and the manifest invariants. The
|
|
32
|
+
* DB CHECK constraints on `skill_bundles.manifest` mirror these.
|
|
33
|
+
*
|
|
34
|
+
* See `references/architecture-decisions.md` (Composition primitives,
|
|
35
|
+
* Skill custody) and `references/development-principles.md` (Agent-first
|
|
36
|
+
* surface design) for the rationale.
|
|
37
|
+
*/
|
|
38
|
+
import type { JsonValue, PlatformCleanupPolicy, PlatformProxyEndpoint, PlatformTemplateEnvironment } from "./submission.js";
|
|
39
|
+
/**
|
|
40
|
+
* Mirrors the CHECK constraint
|
|
41
|
+
* `skill_bundles_id_format_chk = check (id ~ '^skl_[A-Za-z0-9_-]{8,128}$')`
|
|
42
|
+
* defined in supabase/migrations/20260512000000_skill_bundles.sql. Keep
|
|
43
|
+
* the two in lockstep — the DB is the ultimate authority.
|
|
44
|
+
*/
|
|
45
|
+
export declare const SKILL_ID_PATTERN: RegExp;
|
|
46
|
+
/**
|
|
47
|
+
* Human-readable, workspace-scoped name. Lowercase, kebab-friendly,
|
|
48
|
+
* 1..128 chars. The DB enforces the length bound via
|
|
49
|
+
* `skill_bundles_name_len_chk`; this regex tightens the SDK/CLI input
|
|
50
|
+
* surface so callers fail at the boundary rather than in the BFF.
|
|
51
|
+
*/
|
|
52
|
+
export declare const SKILL_NAME_PATTERN: RegExp;
|
|
53
|
+
/**
|
|
54
|
+
* Hard caps applied at upload time. The SDK enforces these before
|
|
55
|
+
* computing the zip hash so a clearly-too-big bundle never wastes
|
|
56
|
+
* bytes-on-the-wire; the BFF re-enforces server-side because the SDK
|
|
57
|
+
* is untrusted. Numbers are deliberately conservative for the MVP and
|
|
58
|
+
* can be tuned later; keep this object as the single tuning point.
|
|
59
|
+
*/
|
|
60
|
+
export declare const SKILL_BUNDLE_LIMITS: {
|
|
61
|
+
/** Compressed (.zip) ceiling. */
|
|
62
|
+
readonly maxCompressedBytes: number;
|
|
63
|
+
/** Sum of uncompressed file sizes. */
|
|
64
|
+
readonly maxDecompressedBytes: number;
|
|
65
|
+
/** Number of regular file entries (directories don't count). */
|
|
66
|
+
readonly maxFiles: 1000;
|
|
67
|
+
/** Maximum directory nesting depth — `a/b/c/d` has depth 4. */
|
|
68
|
+
readonly maxDepth: 16;
|
|
69
|
+
/** Single-entry path length cap. */
|
|
70
|
+
readonly maxPathLength: 512;
|
|
71
|
+
/** Stored file mode for ordinary files. */
|
|
72
|
+
readonly defaultFileMode: 420;
|
|
73
|
+
/** Stored directory mode. */
|
|
74
|
+
readonly defaultDirMode: 493;
|
|
75
|
+
};
|
|
76
|
+
export type SkillRef = WorkspaceSkillRef | ProviderSkillRef;
|
|
77
|
+
export interface WorkspaceSkillRef {
|
|
78
|
+
readonly kind: "workspace";
|
|
79
|
+
readonly id: string;
|
|
80
|
+
}
|
|
81
|
+
export interface ProviderSkillRef {
|
|
82
|
+
readonly kind: "provider";
|
|
83
|
+
readonly vendor: "anthropic" | "custom";
|
|
84
|
+
readonly skillId: string;
|
|
85
|
+
readonly version?: string;
|
|
86
|
+
}
|
|
87
|
+
export declare function isWorkspaceSkillRef(ref: SkillRef): ref is WorkspaceSkillRef;
|
|
88
|
+
export declare function isProviderSkillRef(ref: SkillRef): ref is ProviderSkillRef;
|
|
89
|
+
/**
|
|
90
|
+
* Parse a `SkillRef` from untrusted input. Used by the BFF run parser
|
|
91
|
+
* and by the operations module when deserialising API responses. Throws
|
|
92
|
+
* with a precise path so the caller can surface a usable error.
|
|
93
|
+
*/
|
|
94
|
+
export declare function parseSkillRef(input: unknown, path: string): SkillRef;
|
|
95
|
+
/**
|
|
96
|
+
* Manifest entry persisted in `skill_bundles.manifest` and
|
|
97
|
+
* `run_skill_snapshots.manifest`. `path` is forward-slash, relative,
|
|
98
|
+
* normalised. `mode` is the stored POSIX mode (sanitised, NOT the user's
|
|
99
|
+
* filesystem mode) — see `SKILL_BUNDLE_LIMITS.defaultFileMode`.
|
|
100
|
+
*/
|
|
101
|
+
export interface SkillBundleEntry {
|
|
102
|
+
readonly path: string;
|
|
103
|
+
readonly size: number;
|
|
104
|
+
readonly mode: number;
|
|
105
|
+
}
|
|
106
|
+
export interface SkillBundleManifest {
|
|
107
|
+
readonly entries: readonly SkillBundleEntry[];
|
|
108
|
+
/** Total uncompressed bytes (sum of `entries[i].size`). */
|
|
109
|
+
readonly totalSize: number;
|
|
110
|
+
/** Number of file entries. Equals `entries.length` by construction. */
|
|
111
|
+
readonly fileCount: number;
|
|
112
|
+
}
|
|
113
|
+
export declare class SkillBundleValidationError extends Error {
|
|
114
|
+
constructor(message: string);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Reject input paths that try to escape the bundle root or smuggle
|
|
118
|
+
* platform-specific syntax. Returns the canonical forward-slash
|
|
119
|
+
* relative path; never returns paths starting or ending with `/`.
|
|
120
|
+
*
|
|
121
|
+
* Rejects:
|
|
122
|
+
* - empty strings and pure whitespace
|
|
123
|
+
* - absolute paths (`/foo`, `C:\foo`, `\\server\share`)
|
|
124
|
+
* - backslash separators (Windows)
|
|
125
|
+
* - `..` segments anywhere in the path
|
|
126
|
+
* - `.` segments anywhere except a leading bare `.`
|
|
127
|
+
* - paths whose length exceeds `SKILL_BUNDLE_LIMITS.maxPathLength`
|
|
128
|
+
* - paths whose depth exceeds `SKILL_BUNDLE_LIMITS.maxDepth`
|
|
129
|
+
* - NUL bytes
|
|
130
|
+
*/
|
|
131
|
+
export declare function normaliseSkillBundlePath(input: string): string;
|
|
132
|
+
/**
|
|
133
|
+
* Validate one manifest entry: normalises the path, bounds the size,
|
|
134
|
+
* and sanitises the mode to one of {defaultFileMode, defaultDirMode}.
|
|
135
|
+
* The bundle is files-only, so any non-regular-file entry is rejected
|
|
136
|
+
* upstream by the caller (zip parser must skip symlinks, device files,
|
|
137
|
+
* etc. before reaching this function).
|
|
138
|
+
*/
|
|
139
|
+
export declare function validateSkillBundleEntry(input: {
|
|
140
|
+
readonly path: string;
|
|
141
|
+
readonly size: number;
|
|
142
|
+
readonly mode?: number;
|
|
143
|
+
}): SkillBundleEntry;
|
|
144
|
+
/**
|
|
145
|
+
* Validate a full manifest. Enforces:
|
|
146
|
+
* - entries is a non-empty array
|
|
147
|
+
* - `SKILL.md` exists at the bundle root (Claude's auto-discovery key)
|
|
148
|
+
* - file count <= maxFiles
|
|
149
|
+
* - total uncompressed size <= maxDecompressedBytes
|
|
150
|
+
* - per-entry validation (see `validateSkillBundleEntry`)
|
|
151
|
+
* - no duplicate paths
|
|
152
|
+
*
|
|
153
|
+
* Returns a canonical manifest with totals computed.
|
|
154
|
+
*/
|
|
155
|
+
export declare function validateSkillBundleManifest(input: ReadonlyArray<{
|
|
156
|
+
readonly path: string;
|
|
157
|
+
readonly size: number;
|
|
158
|
+
readonly mode?: number;
|
|
159
|
+
}>): SkillBundleManifest;
|
|
160
|
+
/**
|
|
161
|
+
* The non-secret half of an MCP server declaration. This is what enters
|
|
162
|
+
* the hashed submission, the run snapshot, and any audit log. `name`
|
|
163
|
+
* keys into `secrets.mcpServers` for the per-request headers.
|
|
164
|
+
*/
|
|
165
|
+
export interface McpServerRef {
|
|
166
|
+
readonly name: string;
|
|
167
|
+
readonly url: string;
|
|
168
|
+
}
|
|
169
|
+
export declare const MCP_SERVER_NAME_PATTERN: RegExp;
|
|
170
|
+
/**
|
|
171
|
+
* A Blueprint-level MCP entry. The user is free to supply headers
|
|
172
|
+
* inline; the SDK splits the call site cleanly at submission time so
|
|
173
|
+
* the Authorization (or other auth-bearing) header never enters the
|
|
174
|
+
* non-secret wire payload.
|
|
175
|
+
*/
|
|
176
|
+
export interface BlueprintMcpServer extends McpServerRef {
|
|
177
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
178
|
+
}
|
|
179
|
+
export declare function parseMcpServerRef(input: unknown, path: string): McpServerRef;
|
|
180
|
+
/**
|
|
181
|
+
* What the user authors and passes to `client.submitRun({...blueprint, secrets})`.
|
|
182
|
+
*
|
|
183
|
+
* Blueprint deliberately EXCLUDES `secrets`, `idempotencyKey`, and
|
|
184
|
+
* `signal` so:
|
|
185
|
+
* - `defineRun((p) => Blueprint)` can be reused across calls without
|
|
186
|
+
* re-injecting an API key,
|
|
187
|
+
* - a Blueprint can be JSON-serialised to disk (`antpath run --config
|
|
188
|
+
* run.json`) without ever encoding a credential,
|
|
189
|
+
* - audit / replay tooling can persist a Blueprint as-is.
|
|
190
|
+
*/
|
|
191
|
+
export interface Blueprint {
|
|
192
|
+
readonly model: string;
|
|
193
|
+
readonly system?: string;
|
|
194
|
+
readonly prompt: string | readonly string[];
|
|
195
|
+
readonly skills?: readonly SkillRef[];
|
|
196
|
+
readonly mcpServers?: readonly BlueprintMcpServer[];
|
|
197
|
+
readonly environment?: PlatformTemplateEnvironment;
|
|
198
|
+
readonly cleanup?: PlatformCleanupPolicy;
|
|
199
|
+
readonly proxyEndpoints?: readonly PlatformProxyEndpoint[];
|
|
200
|
+
readonly metadata?: Readonly<Record<string, JsonValue>>;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Currier for parameterised Blueprints.
|
|
204
|
+
*
|
|
205
|
+
* ```ts
|
|
206
|
+
* const investigate = defineRun((p: { repo: string; issue: number }) => ({
|
|
207
|
+
* model: "claude-sonnet-4-5-20250929",
|
|
208
|
+
* system: `You work on ${p.repo}.`,
|
|
209
|
+
* prompt: `Investigate issue #${p.issue}.`,
|
|
210
|
+
* skills: [rules],
|
|
211
|
+
* }));
|
|
212
|
+
* await client.submitRun({
|
|
213
|
+
* ...investigate({ repo: "antpath", issue: 123 }),
|
|
214
|
+
* secrets: { anthropic: { apiKey } },
|
|
215
|
+
* });
|
|
216
|
+
* ```
|
|
217
|
+
*
|
|
218
|
+
* The returned function is referentially transparent — it just calls
|
|
219
|
+
* the provided producer. The wrapper exists for two reasons: (a) a
|
|
220
|
+
* single named entry point makes IDEs surface the type of the inner
|
|
221
|
+
* blueprint at the call site, and (b) it pins the "no late binding"
|
|
222
|
+
* contract — strings inside the Blueprint are resolved by the TS call
|
|
223
|
+
* site, not by a server-side template engine.
|
|
224
|
+
*/
|
|
225
|
+
export declare function defineRun<TParams>(producer: (params: TParams) => Blueprint): (params: TParams) => Blueprint;
|
|
226
|
+
/**
|
|
227
|
+
* Parse a Blueprint from JSON. Defensive — used by the host CLI to
|
|
228
|
+
* load `--config run.json`. Throws with the JSON path that failed so
|
|
229
|
+
* a user can fix their file. Headers are preserved here and split out
|
|
230
|
+
* later by the SDK normalisation step.
|
|
231
|
+
*/
|
|
232
|
+
export declare function parseBlueprint(input: unknown): Blueprint;
|
|
233
|
+
/**
|
|
234
|
+
* Result of splitting a `Blueprint` into the non-secret submission and
|
|
235
|
+
* the secret MCP-headers bundle. The SDK calls this just before posting
|
|
236
|
+
* to /api/runs: the `submission` half is what the BFF hashes for
|
|
237
|
+
* idempotency, the `mcpServerSecrets` half is what enters the Vault.
|
|
238
|
+
*
|
|
239
|
+
* `prompt` is normalised to `readonly string[]` (single-string callers
|
|
240
|
+
* get wrapped in a length-1 array) so the wire payload, the worker, and
|
|
241
|
+
* the audit log don't have to re-handle two shapes.
|
|
242
|
+
*/
|
|
243
|
+
export interface NormalisedBlueprint {
|
|
244
|
+
readonly model: string;
|
|
245
|
+
readonly system?: string;
|
|
246
|
+
readonly prompt: readonly string[];
|
|
247
|
+
readonly skills: readonly SkillRef[];
|
|
248
|
+
readonly mcpServers: readonly McpServerRef[];
|
|
249
|
+
readonly environment?: PlatformTemplateEnvironment;
|
|
250
|
+
readonly cleanup?: PlatformCleanupPolicy;
|
|
251
|
+
readonly proxyEndpoints?: readonly PlatformProxyEndpoint[];
|
|
252
|
+
readonly metadata?: Readonly<Record<string, JsonValue>>;
|
|
253
|
+
/**
|
|
254
|
+
* MCP servers whose Blueprint entry carried `headers`. Keyed by the
|
|
255
|
+
* `name` that appears in `mcpServers` so the BFF can pair them up.
|
|
256
|
+
*/
|
|
257
|
+
readonly mcpServerSecrets: ReadonlyArray<{
|
|
258
|
+
readonly name: string;
|
|
259
|
+
readonly url: string;
|
|
260
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
261
|
+
}>;
|
|
262
|
+
}
|
|
263
|
+
export declare function normaliseBlueprint(blueprint: Blueprint): NormalisedBlueprint;
|