@kudo-dev/sdk 0.0.0-stage → 0.2.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/.env.example ADDED
@@ -0,0 +1,86 @@
1
+ # Environment for an agent started with startAgent (@kudo-dev/sdk/agent).
2
+ # Copy to your agent's folder as .env and fill in. Never commit it.
3
+ #
4
+ # Who the agent is (its system prompt, extra skills and jobs) is code, passed
5
+ # to startAgent. Only secrets and per-deployment values live here.
6
+
7
+ ANTHROPIC_API_KEY=
8
+
9
+ # This agent's signing key. In this PoC it sits in the environment, which
10
+ # means anything that can run a shell in this container can read it —
11
+ # including the agent itself. Covenant asks are written by counterparties, so
12
+ # treat on-chain text as untrusted input.
13
+ PRIVATE_KEY=
14
+
15
+ # The name this agent registers on-chain. Its ERC-8004 id needs no setting:
16
+ # at startup the runtime finds the identity this wallet registered, and a new
17
+ # agent registers one at its first run.
18
+ AGENT_NAME=
19
+ # Where this agent is reachable, registered as ERC-8004 `endpoint` metadata.
20
+ AGENT_ENDPOINT=
21
+
22
+ # --- Robinhood Chain mainnet (chainId 4663) ---
23
+ # The live deployment, and the only one the skills support. USDG here is real
24
+ # money, so start with a throwaway wallet and small amounts.
25
+ RPC_URL=https://rpc.mainnet.chain.robinhood.com
26
+ KUDO=0x1930D0FEaB14b024353bF22adE03Db989aD640C7
27
+ IDENTITY_REGISTRY=0x8004A169FB4a3325136EB29fA0ceB6D2e539a432
28
+
29
+ # --- Gas sponsorship ---
30
+ # The relay that pays this agent's gas while sponsorship runs. Every write tries
31
+ # it first and falls back to a plain transaction (paid in ETH) only when nothing
32
+ # was sent. Empty means Kudo's relay,
33
+ # https://app.kudo.archi/api/sponsor; "off" means always pay your own gas.
34
+ KUDO_SPONSOR_URL=
35
+
36
+ # --- Settlement token ---
37
+ # USDG is an ERC-20 with six decimals, so 1 USDG is 1000000 base units (5 USDG
38
+ # is 5000000; never cast to-wei). ETH is for gas only and is never what a
39
+ # promise is denominated in.
40
+ USDG=0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168
41
+
42
+ # --- Schedule overrides (optional) ---
43
+ # The agent's own `jobs` (passed to startAgent) apply unless one of these is set.
44
+ # JOBS <job>:<seconds>, comma separated, minimum ten seconds.
45
+ # A job the agent defines keeps its own prompt; any
46
+ # other name runs the bundled prompt of that name.
47
+ # TICK_INTERVAL_SECONDS 0 runs no jobs: something else owns this agent's work
48
+ # Jobs share one key, so only one run happens at a time — a run that comes due
49
+ # while another is going waits rather than colliding on the nonce.
50
+ JOBS=
51
+ TICK_INTERVAL_SECONDS=
52
+
53
+ # --- Logging ---
54
+ # Every run logs what started it, each command the agent runs, the output of
55
+ # any that fails, and how it ended (turns, cost, errors). debug also logs every
56
+ # command's output and what the agent said. Secrets are redacted either way.
57
+ LOG_LEVEL=info
58
+
59
+ # --- Phala TEE ---
60
+ # The app id is read at startup from the dstack socket, so leave this blank on
61
+ # Phala. Set it by hand only to exercise the code path locally, where it is
62
+ # reported as unattested and never written on-chain.
63
+ TEE_ID=
64
+
65
+ # --- X / Twitter ---
66
+ # All four are required. If any is missing the request goes out unsigned and X
67
+ # answers 403 "Authenticating with Unknown", which reads like a permissions
68
+ # problem but is not.
69
+ #
70
+ # The access token must be read-write. Setting the app to "Read and write" in
71
+ # the developer portal is not enough — regenerate the access token and secret
72
+ # afterwards, or the old token keeps its read-only permission.
73
+ TWITTER_API_KEY=
74
+ TWITTER_API_SECRET_KEY=
75
+ TWITTER_ACCESS_TOKEN=
76
+ TWITTER_ACCESS_TOKEN_SECRET=
77
+ TWITTER_HANDLE=
78
+
79
+ # --- Older deployments: not supported ---
80
+ # These are earlier Kudo contract versions with a different status enum. The
81
+ # skills and prompts no longer describe them; do not point KUDO at either.
82
+ # mainnet legacy: KUDO=0xc269c6176f3418A84FCdA5911723B0d358971351
83
+ # testnet (46630): RPC_URL=https://rpc.testnet.chain.robinhood.com
84
+ # KUDO=0x7021279517a7b301b8d10eD9c3b9F73C101146f1
85
+ # IDENTITY_REGISTRY=0x8004A818BFB912233c491871b3d84c89A494BD9e
86
+ # USDG=0xc44DB72f7d3185b6AAA7907434592EB7689D0100 (mock)
package/AGENT.md ADDED
@@ -0,0 +1,201 @@
1
+ # Run your own Kudo agent
2
+
3
+ `@kudo-dev/sdk/agent` is everything needed to run an agent that makes and keeps
4
+ Kudo covenants on its own. It runs on the [Claude Agent SDK](https://code.claude.com/docs/en/agent-sdk)
5
+ and works the way a person would at a shell: `cast` for the chain, `node` to
6
+ sign X API requests. There are **no custom tools**; what it knows lives in its
7
+ skills and its system prompt.
8
+
9
+ ```bash
10
+ npm i @kudo-dev/sdk @anthropic-ai/claude-agent-sdk tsx
11
+ ```
12
+
13
+ You also need [`cast`](https://getfoundry.sh) on the `PATH`.
14
+
15
+ ```ts
16
+ // index.ts
17
+ import { startAgent } from "@kudo-dev/sdk/agent";
18
+
19
+ await startAgent({
20
+ systemPrompt: new URL("./system.md", import.meta.url), // who your agent is
21
+ skills: ["chain-forensics"], // added to kudo, kudo-runtime, twitter
22
+ jobs: {
23
+ "settle-due": { interval: 300 }, // a bundled prompt, every 300s
24
+ "watch-bounties": { // a job of your own
25
+ interval: 600,
26
+ prompt: new URL("./watch-bounties.txt", import.meta.url),
27
+ },
28
+ },
29
+ });
30
+ ```
31
+
32
+ ```bash
33
+ cp node_modules/@kudo-dev/sdk/.env.example .env # fill in ANTHROPIC_API_KEY and PRIVATE_KEY
34
+ npx tsx --env-file=.env index.ts
35
+ ```
36
+
37
+ Kudo's own agents are exactly this: see [`agents/shinichi`](../../agents/shinichi)
38
+ and [`agents/megure`](../../agents/megure) in this repository.
39
+
40
+ ## Options
41
+
42
+ | Option | |
43
+ |---|---|
44
+ | `systemPrompt` | who the agent is: text, a path, or a `file:` URL. It is appended to [`prompts/common.md`](prompts/common.md), which every Kudo agent reads first — the covenant model, the honesty rules, how to work at the shell |
45
+ | `skills` | skills beyond the defaults: a name from [`skills/`](skills) or a path / `file:` URL to a skill folder of your own |
46
+ | `jobs` | scheduled jobs by name, each `{ interval, prompt? }`: seconds between runs (at least 10) and the task prompt as text, a path or a `file:` URL. Without `prompt`, a job runs the bundled prompt of its name. Default `{ "settle-due": { interval: 300 } }` |
47
+ | `port` | HTTP port. Default `PORT`, else 3000 |
48
+ | `model` | Claude model id. Default `claude-opus-5` |
49
+ | `cwd` | the agent's shell working directory. Default: the system prompt file's folder |
50
+
51
+ The chain, the key and the API key come from the environment: see
52
+ [`.env.example`](.env.example). It ships set to Robinhood Chain **mainnet**,
53
+ where USDG is real money, so start with a throwaway wallet holding small
54
+ amounts. `JOBS` and `TICK_INTERVAL_SECONDS=0` override the schedule without a
55
+ code change. While Kudo sponsors gas, the agent's writes, payments included,
56
+ cost it nothing: it uses Kudo's relay unless `KUDO_SPONSOR_URL` names another
57
+ (`off` turns it off). When the relay refuses or sponsorship has ended, they
58
+ fall back to ordinary transactions paid in ETH.
59
+
60
+ The agent's ERC-8004 id needs no configuration. At startup the runtime reads
61
+ the Identity Registry's `Registered` events for the agent's wallet and uses
62
+ the identity it finds. A new agent has none, so it registers at its first run
63
+ and the runtime uses that id from then on.
64
+
65
+ ## Skills
66
+
67
+ Every agent gets these three:
68
+
69
+ | Skill | |
70
+ |---|---|
71
+ | [`kudo`](skills/kudo/SKILL.md) | the public Kudo skill: every contract call, the covenant stages, identity. The same file any outside agent reads |
72
+ | [`kudo-runtime`](skills/kudo-runtime/SKILL.md) | this runtime's environment, the preflight, USDG payments and verification, tweet legs, revert selectors, honesty rules |
73
+ | [`twitter`](skills/twitter/SKILL.md) | posting to X: OAuth 1.0a signing with no dependencies, and what each 403 means |
74
+
75
+ Add others by name:
76
+
77
+ | Skill | For |
78
+ |---|---|
79
+ | [`chain-forensics`](skills/chain-forensics/SKILL.md) | following a trail: reading a contract's events without its ABI, tracing ERC-20 transfers, finding who funded a wallet |
80
+ | [`kudo-validation`](skills/kudo-validation/SKILL.md) | the Evaluator only: accepting asks (status `1`) and closing covenants as kept or broken |
81
+
82
+ An agent is given exactly its skills and no others: the runtime loads them as
83
+ one plugin built for that agent, so `kudo-validation` is never even visible to
84
+ an agent that did not ask for it.
85
+
86
+ ## Task prompts
87
+
88
+ A job runs one task prompt on its interval: the `prompt` you gave it, or else
89
+ one of these, bundled, matched by the job's name:
90
+
91
+ | Prompt | Does |
92
+ |---|---|
93
+ | [`take-work`](prompts/take-work.txt) | find one unclaimed open ask, perform it, claim it |
94
+ | [`settle-due`](prompts/settle-due.txt) | keep the promises this agent owes (covenants at status `1`) |
95
+
96
+ A job with no `prompt` and no bundled prompt of its name stops the agent at
97
+ startup. Jobs keep separate schedules but
98
+ share one key, so only one run happens at a time: a run that comes due while
99
+ another is going waits rather than colliding on the nonce. A failed round is
100
+ logged and skipped rather than stopping the schedule, and each job also runs
101
+ once at startup.
102
+
103
+ ## Logs
104
+
105
+ Every line names the run it belongs to: the job's name (or `message`) and a
106
+ short id, so interleaved runs can be told apart.
107
+
108
+ ```
109
+ 10:30:06 [settle-due 3fa1c2] started: Settle every covenant this agent owes…
110
+ 10:30:09 [settle-due 3fa1c2] skill kudo:kudo-runtime
111
+ 10:30:12 [settle-due 3fa1c2] $ cast call $KUDO 'getCovenantsDetails()(…)' --rpc-url $RPC_URL
112
+ 10:30:15 [settle-due 3fa1c2] failed: $ node "$KUDO_SPONSORED_SEND" $USDG "$(cast calldata …)"
113
+ sponsored-send: not sent (403 not_allowed: …) — safe to fall back to cast send
114
+ 10:30:41 [settle-due 3fa1c2] done (35.2s, 9 turns, $0.0912)
115
+ ```
116
+
117
+ By default a run logs:
118
+ - what started it;
119
+ - each command the agent runs and each skill it loads;
120
+ - the output of any command that fails;
121
+ - how it ended: time, turns and cost, or the SDK's error text;
122
+ - any tool it was denied;
123
+ - Claude Code's stderr.
124
+
125
+ `LOG_LEVEL=debug` adds every command's output and what the agent said.
126
+ Secrets (`PRIVATE_KEY`, `ANTHROPIC_API_KEY`, the X credentials) are replaced
127
+ by their names in every line.
128
+
129
+ ## Endpoints
130
+
131
+ | Endpoint | Does |
132
+ |---|---|
133
+ | `POST /message` | `{"message": "..."}` → `{"response": "..."}` — one agent run |
134
+ | `GET /identity` | name, `agentId`, `teeId`, and where to verify the TEE |
135
+ | `GET /health` | liveness |
136
+
137
+ A run can take minutes, so `/message` disables the socket timeout. There is no
138
+ queue: a second request starts a second run.
139
+
140
+ ## Docker and Phala
141
+
142
+ One image per agent, built from the repository root:
143
+
144
+ ```bash
145
+ docker build -f packages/sdk/Dockerfile --build-arg AGENT=agents/shinichi -t kudo-shinichi .
146
+ ```
147
+
148
+ `cast` is baked in from `ghcr.io/foundry-rs/foundry`, pinned by digest, not
149
+ installed at runtime: an agent that bootstraps its own toolchain fails slowly
150
+ and mid-task, and in a TEE it weakens what attestation tells you about the
151
+ image. The build runs `cast --version` so a broken copy fails the build rather
152
+ than the first covenant.
153
+
154
+ [`docker-compose.yml`](docker-compose.yml) is the deployment template. It is
155
+ the file Phala hashes and publishes, so it pins the image **by digest** rather
156
+ than by tag — a tag can be repointed at different bytes later, which would make
157
+ the attestation prove nothing about the code. Push your build and put its
158
+ digest there before deploying. Secrets are `${VARS}` declared in the Phala
159
+ dashboard, never values in the file.
160
+
161
+ ## Verifying what is running
162
+
163
+ In a Phala CVM the agent reads its app id from `/var/run/dstack.sock` at
164
+ startup, registers it as `teeId` metadata on its ERC-8004 identity, and serves
165
+ it from `GET /identity`. The app id is the last path segment of the agent's
166
+ Trust Center report, `https://trust.phala.com/app/<teeId>`. Anyone holding a
167
+ covenant against the agent can open it and see — checked independently of the
168
+ agent — that the code runs on genuine Intel TDX hardware, on an unmodified
169
+ dstack OS, from the compose file and image digest the report names.
170
+
171
+ Outside a TEE there is no app id. The agent still runs; `teeId` and
172
+ `attestation` come back `null`, and it registers its name alone.
173
+
174
+ ## What the agent can and cannot do
175
+
176
+ Allowed: `Bash` and `Skill`, and nothing else. `allowedTools` alone would not
177
+ achieve that — it is an auto-approve list, not a filter — so every other
178
+ built-in tool, and any connector on the API key's account, is denied by name.
179
+ `permissionMode: "dontAsk"` then denies anything not pre-approved, because no
180
+ human is at the keyboard. No project or user settings are read, so nothing on
181
+ the host machine changes what the agent knows.
182
+
183
+ It mints only under an ERC-8004 identity its own wallet owns — the contract
184
+ refuses any other `agentId`. It cannot close covenants unless its wallet holds
185
+ `EVALUATOR_CONTRACT_ROLE`.
186
+
187
+ ## Known limits
188
+
189
+ **The key is in the environment and the agent has a shell**, so the agent can
190
+ read its own key. Covenant asks are written by counterparties and the agent
191
+ reads them from chain, which makes on-chain text an untrusted input path. Fine
192
+ for a proof of concept; before anything real, either move writes behind typed
193
+ tools or put the key behind a signer that enforces amount and recipient policy.
194
+
195
+ **Shell output is not schema-validated.** A typed tool would compute a
196
+ repayment amount in code; here the model composes the whole `cast send`. The
197
+ skills compensate by stating amounts with their token and keeping one numeral
198
+ per promise, but that is a convention, not an enforcement.
199
+
200
+ **Each scheduled round costs a model call.** The loop wakes on a timer and asks
201
+ the agent to look, rather than waking on a chain event.
package/README.md CHANGED
@@ -1,3 +1,124 @@
1
- # Temporary Holding Version
1
+ # @kudo-dev/sdk
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A TypeScript library for [Kudo](https://app.kudo.archi) covenants on
4
+ Robinhood Chain: register an ERC-8004 agent, mint a covenant, meet an ask,
5
+ link proof, and read covenants and agent records.
6
+
7
+ It talks to the Kudo contract and the ERC-8004 registries only. It never
8
+ moves tokens: when a promise is a payment, pay from your own wallet and link
9
+ the transaction hash with `linkProof`. The Kudo MCP server and the ElizaOS
10
+ plugin are built on it.
11
+
12
+ ```bash
13
+ npm install @kudo-dev/sdk viem
14
+ ```
15
+
16
+ **Want an agent that works covenants on its own?** `@kudo-dev/sdk/agent` has
17
+ `startAgent`: give it a system prompt and it runs a Kudo agent on the Claude
18
+ Agent SDK, with the Kudo skills built in. See [AGENT.md](AGENT.md). The library
19
+ below never loads it.
20
+
21
+ ```ts
22
+ import { startAgent } from "@kudo-dev/sdk/agent";
23
+
24
+ await startAgent({ systemPrompt: new URL("./system.md", import.meta.url) });
25
+ ```
26
+
27
+ ## Read
28
+
29
+ ```ts
30
+ import { createKudo } from "@kudo-dev/sdk";
31
+
32
+ const kudo = createKudo(); // Robinhood Chain mainnet, public RPC
33
+
34
+ const asks = await kudo.listOpenAsks({ limit: 10 });
35
+ const covenant = await kudo.getCovenant(109);
36
+ const record = await kudo.agentRecord(20380); // kept vs broken
37
+ const [myId] = await kudo.findAgentIds("0xYourWallet");
38
+ ```
39
+
40
+ ## Write with your own wallet
41
+
42
+ The SDK never stores or asks for a key. Pass any viem wallet client:
43
+
44
+ ```ts
45
+ import { createWalletClient, http } from "viem";
46
+ import { privateKeyToAccount } from "viem/accounts";
47
+ import { createKudo, robinhood } from "@kudo-dev/sdk";
48
+
49
+ const walletClient = createWalletClient({
50
+ account: privateKeyToAccount(process.env.KUDO_PRIVATE_KEY as `0x${string}`),
51
+ chain: robinhood,
52
+ transport: http(),
53
+ });
54
+ const kudo = createKudo({ walletClient });
55
+
56
+ const { agentId } = await kudo.registerAgent({ name: "Ada" }); // once per wallet
57
+ const { covenantId, url } = await kudo.mintCovenant({
58
+ agentId,
59
+ type: "INVOICE",
60
+ ask: "Write a 300-word explainer of ERC-8004 and publish it on IPFS.",
61
+ promise: "I'll pay 5 USDG within one hour of the link going up.",
62
+ });
63
+
64
+ // later, once someone has met the ask:
65
+ const c = await kudo.getCovenant(covenantId); // c.promiseDetail → "pay: 0x…"
66
+ // pay what the promise says from your own wallet (USDG has 6 decimals), then:
67
+ await kudo.linkProof(covenantId, paymentTxHash); // refuses until the Evaluator accepts the ask (IN_PROGRESS), or twice
68
+ await kudo.watchSettlement(covenantId); // resolves when closed
69
+ ```
70
+
71
+ Every write simulates first and throws a `KudoError` that names the revert
72
+ (`NotAuthorizedForAgent`, `AccessForbidden`, …) and says what to do. Writes also
73
+ refuse the common mistakes before they cost gas: minting under an id you do not
74
+ own, meeting an ask someone already met, linking proof on someone else's
75
+ covenant, or registering a second identity.
76
+
77
+ ## Or build unsigned transactions
78
+
79
+ For a hosted service, a browser wallet, a smart account or a remote signer:
80
+
81
+ ```ts
82
+ const tx = kudo.buildMintCovenant({ agentId, type: "LOAN", ask, promise });
83
+ // { to, data, value, chainId, description }
84
+ await kudo.simulate(tx, "0xSigner"); // optional dry-run as the signer
85
+ ```
86
+
87
+ `buildMeetAsk`, `buildLinkProof`, `buildRegisterAgent` and the
88
+ generic `buildTx` work the same way.
89
+
90
+ ## Covenant stages
91
+
92
+ `status` is the contract's field and only the Evaluator moves it: to
93
+ `IN_PROGRESS` when it has checked and accepted the ask's evidence, and to
94
+ `COMPLETED` or `FAILED` when it closes the covenant. Use `stage`:
95
+
96
+ | stage | meaning |
97
+ |---|---|
98
+ | `ask-open` | nobody has met the ask; anyone can take it |
99
+ | `ask-claimed` | someone claimed the ask; the Evaluator has not accepted it, so nothing is owed yet |
100
+ | `promise-due` | the Evaluator accepted the claim (`IN_PROGRESS`); the minter owes the promise now |
101
+ | `awaiting-evaluation` | both legs have proof |
102
+ | `completed` / `failed` | closed by the Evaluator |
103
+
104
+ ## Claims are not protected by the contract
105
+
106
+ Anyone can call `setAskSettlementData` on a covenant again and replace an
107
+ earlier claim; the contract's ask cooldown (`getAskCooldown()`) does not
108
+ prevent it. `meetAsk` therefore refuses an ask that is already met, and after
109
+ mining re-reads the covenant and throws `ALREADY_MET` if the proof on chain is
110
+ not yours. As the promiser, re-read the covenant right before you pay, and pay
111
+ the `promiseDetail` it shows then.
112
+
113
+ ## Configuration
114
+
115
+ `createKudo({ rpcUrl, overrides })`. Robinhood Chain mainnet is the only
116
+ network: older Kudo deployments use a different status enum and are not
117
+ supported.
118
+
119
+ ## Development
120
+
121
+ ```bash
122
+ npm test # offline
123
+ KUDO_LIVE=1 npm test # plus read-only checks against mainnet
124
+ ```
@@ -0,0 +1,94 @@
1
+ declare const DEFAULT_SKILLS: string[];
2
+ /** A bundled skill's name, or a path (or file: URL) to a skill folder with a SKILL.md. */
3
+ type SkillRef = string | URL;
4
+ /** Skills this package ships. */
5
+ declare function bundledSkills(): Promise<string[]>;
6
+ interface SkillPlugin {
7
+ /** The plugin directory to pass to the Agent SDK. */
8
+ path: string;
9
+ /** The skills' names as the SDK lists them, `kudo:<skill>`. */
10
+ names: string[];
11
+ }
12
+
13
+ /** What one agent runs with, fixed at startup. */
14
+ interface AgentSession {
15
+ /** common.md followed by the agent's own system prompt. */
16
+ systemPrompt: string;
17
+ /** The plugin holding exactly this agent's skills. */
18
+ skills: SkillPlugin;
19
+ /** Working directory for the shell: the agent's own folder. */
20
+ cwd: string;
21
+ /** Claude model id. */
22
+ model: string;
23
+ }
24
+ declare class AgentRunError extends Error {
25
+ }
26
+ /**
27
+ * Runs one task to completion and returns everything the agent said.
28
+ * `label` names what started it (a job's name, or `message`) in the log.
29
+ *
30
+ * Throws AgentRunError if the run did not finish — callers decide whether that
31
+ * is a 500 or a logged line.
32
+ */
33
+ declare function runAgent(prompt: string, session: AgentSession, label?: string): Promise<string>;
34
+
35
+ /** Text, or a path / file: URL to read it from. */
36
+ type TextSource = string | URL;
37
+ /**
38
+ * The agent's standing instructions: the shared base, then its character.
39
+ *
40
+ * Order matters. The character comes last so that where the two touch - voice,
41
+ * register, what it will and will not claim - the specific one is what the
42
+ * model read most recently.
43
+ */
44
+ declare function loadSystemPrompt(character: TextSource): Promise<string>;
45
+ /** Task prompts this package ships. */
46
+ declare function bundledPrompts(): Promise<string[]>;
47
+ /** A job's task prompt: its own if it has one, else this package's prompt of that name. */
48
+ declare function loadPrompt(name: string, own?: TextSource): Promise<string>;
49
+
50
+ /** One scheduled job, as an agent passes it to startAgent. */
51
+ interface AgentJob {
52
+ /** Seconds between runs, at least ten. */
53
+ interval: number;
54
+ /** The task prompt: text, a path or a file: URL. Default: the bundled prompt of the job's name. */
55
+ prompt?: TextSource;
56
+ }
57
+ interface JobSpec {
58
+ name: string;
59
+ intervalSeconds: number;
60
+ /** The job's own prompt; undefined means the bundled one named `name`. */
61
+ prompt?: TextSource;
62
+ }
63
+ /** The jobs to run: JOBS if set, none if TICK_INTERVAL_SECONDS is 0, else the agent's own. */
64
+ declare function resolveJobs(own: Record<string, AgentJob> | undefined, env?: NodeJS.ProcessEnv): JobSpec[];
65
+
66
+ interface AgentOptions {
67
+ /** Who this agent is: the text, or a path / file: URL to it (e.g. `new URL("./system.md", import.meta.url)`). */
68
+ systemPrompt: TextSource;
69
+ /**
70
+ * Skills beyond the defaults (`kudo`, `kudo-runtime`, `twitter`): the name of
71
+ * one this package ships (`chain-forensics`, `kudo-validation`) or a path /
72
+ * file: URL to a skill folder of your own.
73
+ */
74
+ skills?: SkillRef[];
75
+ /**
76
+ * Scheduled jobs by name, each `{ interval, prompt? }`: seconds between runs
77
+ * and the task prompt (text, a path or a file: URL). A job without a prompt
78
+ * runs the bundled one of its name (`take-work`, `settle-due`). Default
79
+ * `{ "settle-due": { interval: 300 } }`; JOBS overrides the schedule.
80
+ */
81
+ jobs?: Record<string, AgentJob>;
82
+ /** HTTP port. Default PORT, else 3000. */
83
+ port?: number;
84
+ /** Claude model id. Default `claude-opus-5`. */
85
+ model?: string;
86
+ /** Working directory for the agent's shell. Default: the system prompt file's folder, else the current one. */
87
+ cwd?: string;
88
+ }
89
+ /** The fixed parts of a run: system prompt, skills, working directory, model. */
90
+ declare function createSession(options: AgentOptions): Promise<AgentSession>;
91
+ /** Starts the agent: the HTTP endpoint and its scheduled jobs. Resolves once both are running. */
92
+ declare function startAgent(options: AgentOptions): Promise<void>;
93
+
94
+ export { type AgentJob, type AgentOptions, AgentRunError, type AgentSession, DEFAULT_SKILLS, type JobSpec, type SkillRef, type TextSource, bundledPrompts, bundledSkills, createSession, loadPrompt, loadSystemPrompt, resolveJobs, runAgent, startAgent };