@noodleseed/agent-kit 0.9.0 → 0.11.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/README.md +4 -3
- package/manifest.json +25 -15
- package/package.json +1 -1
- package/skills/claude-code/SKILL.md +14 -8
- package/skills/claude-code/references/agent-contract.md +43 -0
- package/skills/claude-code/references/authoring-workflow.md +43 -0
- package/skills/claude-code/references/compile-errors.md +1 -29
- package/skills/claude-code/references/deploy-and-ops.md +20 -0
- package/skills/claude-code/references/examples.md +1 -1
- package/skills/claude-code/references/sdk-surface.md +134 -9
- package/skills/claude-code/references/widgets-and-apps.md +177 -30
- package/skills/codex/SKILL.md +14 -8
- package/skills/codex/references/agent-contract.md +43 -0
- package/skills/codex/references/authoring-workflow.md +43 -0
- package/skills/codex/references/compile-errors.md +1 -29
- package/skills/codex/references/deploy-and-ops.md +20 -0
- package/skills/codex/references/examples.md +1 -1
- package/skills/codex/references/sdk-surface.md +134 -9
- package/skills/codex/references/widgets-and-apps.md +177 -30
package/README.md
CHANGED
|
@@ -8,9 +8,10 @@ into a project's `.agents/` and `.claude/` skill directories via `noodle agents
|
|
|
8
8
|
|
|
9
9
|
## Contents
|
|
10
10
|
|
|
11
|
-
- `skills/codex/` — the Codex (Codex CLI / AGENTS.md) skill: a `SKILL.md` router plus
|
|
12
|
-
`references/*.md` files (sdk-surface, cli-commands,
|
|
13
|
-
widgets-and-apps, test-in-hosts, troubleshooting, deploy-and-ops, publishing,
|
|
11
|
+
- `skills/codex/` — the Codex (Codex CLI / AGENTS.md) skill: a `SKILL.md` router plus eleven
|
|
12
|
+
`references/*.md` files (sdk-surface, cli-commands, agent-contract, compile-errors,
|
|
13
|
+
authoring-workflow, widgets-and-apps, test-in-hosts, troubleshooting, deploy-and-ops, publishing,
|
|
14
|
+
examples).
|
|
14
15
|
- `skills/claude-code/` — the Claude Code skill, same hierarchical tree.
|
|
15
16
|
- `manifest.json` — `{ packageVersion, files: [{ path, sha256, agentTarget }] }`. The CLI verifies every
|
|
16
17
|
file's sha256 against this manifest before writing it into a user's project; a mismatch refuses the
|
package/manifest.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
"packageVersion": "0.
|
|
2
|
+
"packageVersion": "0.11.0",
|
|
3
3
|
"files": [
|
|
4
4
|
{
|
|
5
5
|
"path": "skills/codex/SKILL.md",
|
|
6
|
-
"sha256": "
|
|
6
|
+
"sha256": "54f2a9d84455361127f40fe079715ec69c1ef737b491fc2ace896cb754ff4fe3",
|
|
7
7
|
"agentTarget": "codex"
|
|
8
8
|
},
|
|
9
9
|
{
|
|
10
10
|
"path": "skills/codex/references/sdk-surface.md",
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "d5da0c1ec33aa8d2770e145293174e99cff0c73264756dafe121e818ade14abf",
|
|
12
12
|
"agentTarget": "codex"
|
|
13
13
|
},
|
|
14
14
|
{
|
|
@@ -16,19 +16,24 @@
|
|
|
16
16
|
"sha256": "c50bf5ec6f43bd9fb7115ea9c9eb8de33c93e123f3e2d396785fe75ba094d40d",
|
|
17
17
|
"agentTarget": "codex"
|
|
18
18
|
},
|
|
19
|
+
{
|
|
20
|
+
"path": "skills/codex/references/agent-contract.md",
|
|
21
|
+
"sha256": "8e884a90f7c155a9f1d3773c7c037f88a98ac8d5c5d23e8100349ae82d068e6d",
|
|
22
|
+
"agentTarget": "codex"
|
|
23
|
+
},
|
|
19
24
|
{
|
|
20
25
|
"path": "skills/codex/references/compile-errors.md",
|
|
21
|
-
"sha256": "
|
|
26
|
+
"sha256": "22692f2fda9c7d8ef0aa54e58148d22cf740bf722ceb79a942f6f146009a6bda",
|
|
22
27
|
"agentTarget": "codex"
|
|
23
28
|
},
|
|
24
29
|
{
|
|
25
30
|
"path": "skills/codex/references/authoring-workflow.md",
|
|
26
|
-
"sha256": "
|
|
31
|
+
"sha256": "ad5866ad739885592eb729fdd0bf18d602b886021309e28565a090d66f7c2e9a",
|
|
27
32
|
"agentTarget": "codex"
|
|
28
33
|
},
|
|
29
34
|
{
|
|
30
35
|
"path": "skills/codex/references/widgets-and-apps.md",
|
|
31
|
-
"sha256": "
|
|
36
|
+
"sha256": "dea06536f780f0bb6d26dc63a6f1f35e2d6eb97f7a9c1c8574ed7377ccfe37a8",
|
|
32
37
|
"agentTarget": "codex"
|
|
33
38
|
},
|
|
34
39
|
{
|
|
@@ -43,7 +48,7 @@
|
|
|
43
48
|
},
|
|
44
49
|
{
|
|
45
50
|
"path": "skills/codex/references/deploy-and-ops.md",
|
|
46
|
-
"sha256": "
|
|
51
|
+
"sha256": "0175101939ca5ea6823a18ce83a32311f5d9937ef8469a431dd0576ad0997fe4",
|
|
47
52
|
"agentTarget": "codex"
|
|
48
53
|
},
|
|
49
54
|
{
|
|
@@ -53,17 +58,17 @@
|
|
|
53
58
|
},
|
|
54
59
|
{
|
|
55
60
|
"path": "skills/codex/references/examples.md",
|
|
56
|
-
"sha256": "
|
|
61
|
+
"sha256": "9f3ce479669040f0c58c9876b2bbca90821c69a760d0b020a56072bd6e549d73",
|
|
57
62
|
"agentTarget": "codex"
|
|
58
63
|
},
|
|
59
64
|
{
|
|
60
65
|
"path": "skills/claude-code/SKILL.md",
|
|
61
|
-
"sha256": "
|
|
66
|
+
"sha256": "fa975102477cd02ecdb083b4b8f747fc3fee3a7bcb5b725fe63ca9504258ba39",
|
|
62
67
|
"agentTarget": "claude-code"
|
|
63
68
|
},
|
|
64
69
|
{
|
|
65
70
|
"path": "skills/claude-code/references/sdk-surface.md",
|
|
66
|
-
"sha256": "
|
|
71
|
+
"sha256": "d5da0c1ec33aa8d2770e145293174e99cff0c73264756dafe121e818ade14abf",
|
|
67
72
|
"agentTarget": "claude-code"
|
|
68
73
|
},
|
|
69
74
|
{
|
|
@@ -71,19 +76,24 @@
|
|
|
71
76
|
"sha256": "c50bf5ec6f43bd9fb7115ea9c9eb8de33c93e123f3e2d396785fe75ba094d40d",
|
|
72
77
|
"agentTarget": "claude-code"
|
|
73
78
|
},
|
|
79
|
+
{
|
|
80
|
+
"path": "skills/claude-code/references/agent-contract.md",
|
|
81
|
+
"sha256": "8e884a90f7c155a9f1d3773c7c037f88a98ac8d5c5d23e8100349ae82d068e6d",
|
|
82
|
+
"agentTarget": "claude-code"
|
|
83
|
+
},
|
|
74
84
|
{
|
|
75
85
|
"path": "skills/claude-code/references/compile-errors.md",
|
|
76
|
-
"sha256": "
|
|
86
|
+
"sha256": "22692f2fda9c7d8ef0aa54e58148d22cf740bf722ceb79a942f6f146009a6bda",
|
|
77
87
|
"agentTarget": "claude-code"
|
|
78
88
|
},
|
|
79
89
|
{
|
|
80
90
|
"path": "skills/claude-code/references/authoring-workflow.md",
|
|
81
|
-
"sha256": "
|
|
91
|
+
"sha256": "ad5866ad739885592eb729fdd0bf18d602b886021309e28565a090d66f7c2e9a",
|
|
82
92
|
"agentTarget": "claude-code"
|
|
83
93
|
},
|
|
84
94
|
{
|
|
85
95
|
"path": "skills/claude-code/references/widgets-and-apps.md",
|
|
86
|
-
"sha256": "
|
|
96
|
+
"sha256": "dea06536f780f0bb6d26dc63a6f1f35e2d6eb97f7a9c1c8574ed7377ccfe37a8",
|
|
87
97
|
"agentTarget": "claude-code"
|
|
88
98
|
},
|
|
89
99
|
{
|
|
@@ -98,7 +108,7 @@
|
|
|
98
108
|
},
|
|
99
109
|
{
|
|
100
110
|
"path": "skills/claude-code/references/deploy-and-ops.md",
|
|
101
|
-
"sha256": "
|
|
111
|
+
"sha256": "0175101939ca5ea6823a18ce83a32311f5d9937ef8469a431dd0576ad0997fe4",
|
|
102
112
|
"agentTarget": "claude-code"
|
|
103
113
|
},
|
|
104
114
|
{
|
|
@@ -108,7 +118,7 @@
|
|
|
108
118
|
},
|
|
109
119
|
{
|
|
110
120
|
"path": "skills/claude-code/references/examples.md",
|
|
111
|
-
"sha256": "
|
|
121
|
+
"sha256": "9f3ce479669040f0c58c9876b2bbca90821c69a760d0b020a56072bd6e549d73",
|
|
112
122
|
"agentTarget": "claude-code"
|
|
113
123
|
}
|
|
114
124
|
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noodleseed/agent-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Self-checking, self-updating agent skills for the Noodle Seed CLI. Authored in this repo by @noodle-borg/agent-kit; this is the published, independently-versioned canonical skills artifact the CLI fetches and verifies.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: noodle-seed
|
|
3
3
|
description: Use when building, validating, testing, deploying, or operating a local or hosted Noodle Seed MCP server or app authored in TypeScript with the noodle CLI.
|
|
4
|
-
version: 0.
|
|
5
|
-
hash:
|
|
4
|
+
version: 0.11.0
|
|
5
|
+
hash: 5aa15e5bf381543c
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Noodle Seed
|
|
@@ -13,17 +13,23 @@ Use this skill for project-local Noodle Seed authoring in Claude Code; preserve
|
|
|
13
13
|
|
|
14
14
|
## Golden path
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
This CLI is agent-native: the cold-agent-path commands speak the `--json` envelope (hosted admin/ops commands are still being normalized). Drive the loop by parsing machine state, not human prose. The full envelope, exit codes, and output modes are in `references/agent-contract.md`.
|
|
17
|
+
|
|
18
|
+
1. **Discover** — `noodle commands --json`: every command, subcommand, flag, and exit code (don't read source).
|
|
19
|
+
2. **Author** — edit `src/server.ts` (the configured entrypoint); follow the capability recipe in `references/sdk-surface.md` and `references/examples.md`.
|
|
20
|
+
3. **Validate** — `noodle validate --json`; on failure `{ok:false,error:{code,message,fix,next,errors:[{code,path,message}]}}` — the per-field detail is in `error.errors[]`.
|
|
21
|
+
4. **Repair** — fix each `error.errors[]` entry at its `path`, then re-run `noodle validate --json`; `noodle validate --fix-prompt` emits ready-to-apply repair prose. Never freeform re-edit (see `references/compile-errors.md`).
|
|
22
|
+
5. **Smoke** — `noodle test --json`: local compile plus a loopback MCP smoke.
|
|
23
|
+
6. **Apps/widgets** — `noodle check --json` (add `--target chatgpt|claude`), then `noodle devtools` (see `references/widgets-and-apps.md`).
|
|
24
|
+
7. **Deploy** — `noodle deploy`; auth fails clean with `error.next` = `noodle login` (see `references/deploy-and-ops.md`).
|
|
25
|
+
8. **Wire into a host** — `noodle connect <codex|claude-code|chatgpt>` (prove it in a real host per `references/test-in-hosts.md`; debug symptoms with `references/troubleshooting.md`).
|
|
26
|
+
9. **Health** — `noodle metrics --agent-output`: a health verdict plus the exact next command per attention item.
|
|
22
27
|
|
|
23
28
|
## References
|
|
24
29
|
|
|
25
30
|
Load these on demand:
|
|
26
31
|
|
|
32
|
+
- `references/agent-contract.md` — the `--json` envelope, exit codes, and the three output modes.
|
|
27
33
|
- `references/sdk-surface.md` — what to import from `@noodleseed/one` and which builder to use.
|
|
28
34
|
- `references/cli-commands.md` — every `noodle` command, grouped by area.
|
|
29
35
|
- `references/compile-errors.md` — fix `noodle validate` errors by code.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Agent contract: --json, exit codes, output modes
|
|
2
|
+
|
|
3
|
+
The cold-agent-path commands (`init`, `validate`, `test`, `check`, `tools`/`resources`/`prompts`, `deploy`, `metrics`, `events`, `agents`) are agent-native and return the envelope below; hosted admin/ops commands (`status`, `inspect`, `smoke`, `logs`, `update`) are still being normalized. Decide what to do next by parsing machine state — do not scrape human prose.
|
|
4
|
+
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- Response envelope
|
|
8
|
+
- Exit codes
|
|
9
|
+
- Output modes
|
|
10
|
+
- Repair loop
|
|
11
|
+
|
|
12
|
+
## Response envelope
|
|
13
|
+
|
|
14
|
+
A `--json` command returns exactly one JSON object:
|
|
15
|
+
|
|
16
|
+
- **Success**: `{ ok: true, data, warnings? }` — `data` is the command payload; `warnings?` is an optional array of non-fatal notes.
|
|
17
|
+
- **Failure**: `{ ok: false, error: { code, message, cause?, fix, next, requestId? } }` — `code` is the stable machine code to branch on, `message` is human text, `cause?` is the underlying error, `fix` states the correction, `next` names the command to run next, `requestId?` correlates a hosted call.
|
|
18
|
+
- **Field errors** carry a dotted `path`: multi-error commands (e.g. `noodle validate`) nest them under `error.errors[]`, each `{ code, path, message }`. The top-level `error` still carries `code`/`message`/`fix`/`next`; the per-field `path`s live in `error.errors[]`.
|
|
19
|
+
- **Repair prose is isolated**: ready-to-apply repair text appears only under `error.fixPrompt` (surfaced by `--fix-prompt`), never mixed into `message` or `data`.
|
|
20
|
+
|
|
21
|
+
## Exit codes
|
|
22
|
+
|
|
23
|
+
Branch on the process exit code before parsing the body:
|
|
24
|
+
|
|
25
|
+
| Code | Meaning |
|
|
26
|
+
| :-- | :-- |
|
|
27
|
+
| `0` | ok |
|
|
28
|
+
| `1` | failure (command ran, the work failed) |
|
|
29
|
+
| `2` | usage (bad flags or arguments) |
|
|
30
|
+
| `3` | auth (login or permission required) |
|
|
31
|
+
| `4` | unreachable (service or network) |
|
|
32
|
+
| `5` | mcp/tool-call error (a `tools`/`resources`/`prompts`/`test` smoke call failed) |
|
|
33
|
+
|
|
34
|
+
## Output modes
|
|
35
|
+
|
|
36
|
+
Two kinds of output — never mix them:
|
|
37
|
+
|
|
38
|
+
- `--json` — **machine state**: the envelope above. Use it to decide what to do next.
|
|
39
|
+
- `--fix-prompt` / `--agent-output` (aliases) — **agent-readable text**, not the envelope: a ready-to-apply repair prompt for authoring commands (`validate`/`test`/`check`), or an operational `health` verdict (`ok`/`attention`) with `attention[]` next-commands for ops commands (`metrics`/`doctor`/`alerts`). Use it to author a fix or judge a running deployment.
|
|
40
|
+
|
|
41
|
+
## Repair loop
|
|
42
|
+
|
|
43
|
+
On a `validate` failure: parse `error.code` + `path`, fix exactly that field in `src/server.ts`, then re-run `noodle validate --json`. Never freeform re-edit. Repeat until `ok: true`, then `noodle test --json`.
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
- Repair loop
|
|
8
8
|
- Connectors
|
|
9
9
|
- HTTP connector example
|
|
10
|
+
- Worked example (full server)
|
|
10
11
|
- Compute connector example
|
|
11
12
|
- Tests
|
|
12
13
|
- Secrets and variables
|
|
@@ -39,6 +40,8 @@ HTTP connector auth variants: `bearer` (`{ kind: "bearer", secret: secret("API_T
|
|
|
39
40
|
|
|
40
41
|
## HTTP connector example
|
|
41
42
|
|
|
43
|
+
The operation mapping in detail: `request` templates the outbound call, `response` maps the HTTP body into your typed `output`.
|
|
44
|
+
|
|
42
45
|
```ts
|
|
43
46
|
import { connector, secret, variable } from '@noodleseed/one';
|
|
44
47
|
|
|
@@ -71,6 +74,46 @@ const crm = connector('crm').version('1.0.0').http({
|
|
|
71
74
|
|
|
72
75
|
Use `${args.field}` for tool/operation inputs and `${response.body.path}` for response mapping. Prefer explicit `allowedOrigins`; OAuth token/session URLs must also be on an allowed origin. For client credentials use `{ kind: "oauth2ClientCredentials", tokenUrl, clientId, clientSecret, scopes? }`; for per-customer downstream calls use `delegatedOAuth` or `delegatedSessionCookie` with a matching `customerAuth` server option.
|
|
73
76
|
|
|
77
|
+
## Worked example (full server)
|
|
78
|
+
|
|
79
|
+
Declare the API as data, bind it with `use`, then record a call in a tool. `auth` reads a managed `secret(...)` — never inline a key. Map the HTTP body into your typed `output` with `${response...}`.
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import { connector, secret, server, tool, z } from '@noodleseed/one';
|
|
83
|
+
|
|
84
|
+
const crm = connector('acme_crm')
|
|
85
|
+
.version('1.0.0')
|
|
86
|
+
.http({
|
|
87
|
+
baseUrl: 'https://api.acme.example',
|
|
88
|
+
allowedOrigins: ['https://api.acme.example'],
|
|
89
|
+
auth: { kind: 'apiKey', header: 'X-Api-Key', secret: secret('ACME_CRM_TOKEN') },
|
|
90
|
+
operations: {
|
|
91
|
+
get_ticket: {
|
|
92
|
+
type: 'read',
|
|
93
|
+
method: 'GET',
|
|
94
|
+
path: '/v1/tickets/{id}',
|
|
95
|
+
input: { id: { type: 'string', required: true } },
|
|
96
|
+
output: { subject: { type: 'string' }, status: { type: 'string' } },
|
|
97
|
+
response: { subject: '${response.data.subject}', status: '${response.data.state}' },
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
export default server('support', { title: 'Support', version: '1.0.0', use: { crm } }, [
|
|
103
|
+
tool('ticket_status', {
|
|
104
|
+
description: 'Look up a support ticket by id.',
|
|
105
|
+
input: z.object({ ticket_id: z.string() }),
|
|
106
|
+
output: z.object({ subject: z.string(), status: z.string() }),
|
|
107
|
+
fulfil: ({ input, connectors }) => {
|
|
108
|
+
const ticket = connectors.crm.get_ticket({ id: input.ticket_id });
|
|
109
|
+
return { subject: ticket.subject, status: ticket.status };
|
|
110
|
+
},
|
|
111
|
+
}),
|
|
112
|
+
]);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
More: `auth.kind` is `bearer` | `apiKey` (needs `header`) | `oauth2ClientCredentials` | `delegatedOAuth` | `delegatedSessionCookie`. Use `.compute(name, { input, output, run })` for a sandboxed transform; `provides:` (instead of `use:`) exposes a connector only to compute `callOperation`; and `noodle import openapi <file>` generates a connector from an OpenAPI spec.
|
|
116
|
+
|
|
74
117
|
## Compute connector example
|
|
75
118
|
|
|
76
119
|
```ts
|
|
@@ -3,39 +3,11 @@
|
|
|
3
3
|
## Contents
|
|
4
4
|
|
|
5
5
|
- The repair loop
|
|
6
|
-
- JSON shape
|
|
7
|
-
- Fix prompt
|
|
8
6
|
- Error codes
|
|
9
7
|
|
|
10
8
|
## The repair loop
|
|
11
9
|
|
|
12
|
-
Run `noodle validate` (add `--json` for machine-readable
|
|
13
|
-
|
|
14
|
-
## JSON shape
|
|
15
|
-
|
|
16
|
-
Use `noodle validate --json` in automated repair loops. Treat `errors[]` as the work queue and change only the cited file/path before re-running validation.
|
|
17
|
-
|
|
18
|
-
```json
|
|
19
|
-
{
|
|
20
|
-
"ok": false,
|
|
21
|
-
"errors": [
|
|
22
|
-
{
|
|
23
|
-
"code": "unknown_operation",
|
|
24
|
-
"path": "tools.search.fulfil.steps.0.operation",
|
|
25
|
-
"message": "Unknown connector operation.",
|
|
26
|
-
"expected": "operation declared on connector alias `crm`",
|
|
27
|
-
"got": "crm.find_customer",
|
|
28
|
-
"didYouMean": "crm.findCustomer",
|
|
29
|
-
"suggestions": ["crm.findCustomer"],
|
|
30
|
-
"docAnchor": "connectors.operations"
|
|
31
|
-
}
|
|
32
|
-
]
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Fix prompt
|
|
37
|
-
|
|
38
|
-
`noodle validate --fix-prompt` prints a compact agent repair prompt with the same structured errors. Use it when delegating a repair pass, but still inspect the resulting code and re-run `noodle validate --json`.
|
|
10
|
+
Run `noodle validate` (add `--json` for the machine-readable envelope, `--fix-prompt` for an agent repair prompt). On failure the envelope is `{ok:false,error:{code,message,fix,next,errors:[{code,path,message}]}}`: each entry in `error.errors[]` carries a `code`, a dotted `path` to the offending field, and a `message`; many also carry `expected`/`got`, `didYouMean`/`suggestions`, and a `docAnchor` (the full envelope is in `agent-contract.md`). Fix the specific error the `path` locates, then re-validate. Do not freeform re-edit. Once `noodle validate` passes, run `noodle test`, then `noodle dev`.
|
|
39
11
|
|
|
40
12
|
## Error codes
|
|
41
13
|
|
|
@@ -5,10 +5,12 @@
|
|
|
5
5
|
- Authenticate
|
|
6
6
|
- Link and target
|
|
7
7
|
- Deploy and inspect
|
|
8
|
+
- Connect into a host
|
|
8
9
|
- Access modes
|
|
9
10
|
- Org and members
|
|
10
11
|
- Config and observability
|
|
11
12
|
- Agent-safe CLI recipes
|
|
13
|
+
- Analytics
|
|
12
14
|
|
|
13
15
|
## Authenticate
|
|
14
16
|
|
|
@@ -22,6 +24,24 @@
|
|
|
22
24
|
|
|
23
25
|
`noodle deploy` deploys the server. Then `noodle open` (latest URL), `noodle status`, `noodle inspect` (metadata, no secrets), `noodle smoke` (readiness diagnostics), and `noodle rollback <deploymentId>` to revert.
|
|
24
26
|
|
|
27
|
+
## Connect into a host
|
|
28
|
+
|
|
29
|
+
Once deployed, register the server as a tool in a host with `noodle connect <host>` (`claude-code`, `codex`, `chatgpt`, `cursor`, `vscode`, `claude`, `inspector`) — it prints the exact config to paste.
|
|
30
|
+
|
|
31
|
+
- **Claude Code / Claude Desktop** (verified) — add the `mcpServers` block, or one-shot `claude mcp add-json noodle-server '<json>'`:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"mcpServers": {
|
|
36
|
+
"noodle-server": { "type": "https", "url": "https://<app>.mcp.noodleseed.dev" }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- **Codex / Cursor / VS Code** — the same `mcpServers` block is emitted as a starting point (these hosts' config formats are not officially documented). Wiring a deployed Noodle server into Codex means registering that block in Codex's MCP config.
|
|
42
|
+
- **ChatGPT / Claude.ai** — no config file: open the host's Settings → Connectors → Add custom connector, paste the MCP URL, then authenticate.
|
|
43
|
+
- `noodle connect codex|claude-code --write` writes the project-local agent files (only these two targets).
|
|
44
|
+
|
|
25
45
|
## Access modes
|
|
26
46
|
|
|
27
47
|
`noodle access set owner-only|org-members|authenticated|customers` controls who can call the deployed server. Hosted access is identity-based; never add static data-plane keys.
|
|
@@ -6,7 +6,7 @@ Flagship examples (one per capability). Read the matching example for the patter
|
|
|
6
6
|
| :-- | :-- |
|
|
7
7
|
| `hello` | Minimal TypeScript quickstart — a single tool, no connectors/widgets. |
|
|
8
8
|
| `weather` | HTTP connectors, multi-step flows, and the sandboxed compute connector. |
|
|
9
|
-
| `
|
|
9
|
+
| `food-ordering` | Consumer ordering MCP App widgets, app-only helpers, cart state, assets, branding, and handoff. |
|
|
10
10
|
| `customer-auth` | End-user (customer) auth via OIDC/Firebase bridge with delegated credentials. |
|
|
11
11
|
| `stateful-draft` | Durable, caller-scoped widget state handles with optimistic revisions. |
|
|
12
12
|
| `perplexity` | A real SaaS API with bearer auth and a managed `secret`. |
|
|
@@ -3,43 +3,51 @@
|
|
|
3
3
|
Import these from `@noodleseed/one`. They are declarative builders that emit manifest data — do not hand-author the manifest or runtime artifacts. React view helpers come from `@noodleseed/one/react` (`generateHelpers`); the hook surface is documented in `widgets-and-apps.md`.
|
|
4
4
|
Platform helper connectors are explicit subpath imports from `@noodleseed/one/platform` (`noodlePlatform`, `noodlePlatformCatalog`) when an app needs first-party hosted state APIs.
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## Contents
|
|
7
|
+
|
|
8
|
+
- Exports by area
|
|
9
|
+
- Authoring signatures
|
|
10
|
+
- Recipes
|
|
11
|
+
|
|
12
|
+
## Exports by area
|
|
13
|
+
|
|
14
|
+
### Server & tools
|
|
7
15
|
|
|
8
16
|
- `server(name, options, definitions)` — the server/app root.
|
|
9
17
|
- `tool(name, { description, input, output, fulfil })` — a model-visible tool.
|
|
10
18
|
- `toolWithWidget(name, { ..., view })` — a model-visible tool that renders an MCP Apps widget.
|
|
11
19
|
- `toolForWidget(name, { ... })` — a widget-only helper tool, hidden from the model.
|
|
12
20
|
|
|
13
|
-
|
|
21
|
+
### Widgets & assets
|
|
14
22
|
|
|
15
23
|
- `widget(...)` — declare a widget/view component.
|
|
16
24
|
- `asset("./path")` — reference a packaged asset (e.g. an image).
|
|
17
25
|
- `annotations(...)` — tool/Apps annotation metadata.
|
|
18
26
|
|
|
19
|
-
|
|
27
|
+
### Connectors & flows
|
|
20
28
|
|
|
21
29
|
- `connector("id").version(...).http({...})` or `.compute(...)` — declarative data connectors.
|
|
22
30
|
- `when(...)` — declarative conditions for recorded flows (no native branching on runtime values).
|
|
23
31
|
|
|
24
|
-
|
|
32
|
+
### Resources & prompts
|
|
25
33
|
|
|
26
34
|
- `resource(name, { ... })` — an MCP resource.
|
|
27
35
|
- `prompt(name, { ... })` — an MCP prompt.
|
|
28
36
|
|
|
29
|
-
|
|
37
|
+
### Managed config
|
|
30
38
|
|
|
31
39
|
- `secret("NAME")` — reference a managed secret (operated via `noodle secrets`).
|
|
32
40
|
- `variable("NAME")` — reference a managed variable (operated via `noodle variables`).
|
|
33
41
|
|
|
34
|
-
|
|
42
|
+
### Customer auth
|
|
35
43
|
|
|
36
44
|
- `customerAuth.oidc(...)`, `.firebase(...)`, `.microsoft(...)`, or `.bridge(...)` — end-user/customer identity for `--access customers` deployments.
|
|
37
45
|
|
|
38
|
-
|
|
46
|
+
### Sessions
|
|
39
47
|
|
|
40
48
|
- `handoffSession(...)` — typed cross-host handoff session envelopes.
|
|
41
49
|
|
|
42
|
-
|
|
50
|
+
### Schemas
|
|
43
51
|
|
|
44
52
|
- `z` — Zod, for input/output schemas (compiles to JSON Schema 2020-12).
|
|
45
53
|
|
|
@@ -52,4 +60,121 @@ Platform helper connectors are explicit subpath imports from `@noodleseed/one/pl
|
|
|
52
60
|
- `resource(name, { uri, description?, mimeType?, fulfil })` and `prompt(name, { description?, arguments?, fulfil })` expose MCP resources/prompts.
|
|
53
61
|
- `widget(name, { title, view, csp?, domain?, permissions? })` declares reusable view metadata; `asset("./path")` packages local files.
|
|
54
62
|
- `customerAuth.*(...)` belongs in `server` options when deployed customer callers need verified identity; inspect `examples/customer-auth` or `examples/sharepoint` before using it.
|
|
55
|
-
- `state` defines durable widget state handles; `handoff` declares allowed external domains for safe host handoff.
|
|
63
|
+
- `state` defines durable widget state handles; `handoff` declares allowed external domains for safe host handoff.
|
|
64
|
+
|
|
65
|
+
## Recipes
|
|
66
|
+
|
|
67
|
+
Minimal, complete, compiling recipes — author in `src/server.ts`, then `noodle validate`. Inside a `fulfil`, `ctx.input` (a prompt’s arguments or a templated resource’s URI variables) and `ctx.connectors` are **symbolic**: reference them to record a flow. Recording is not execution, so never branch on their runtime values with native `if` — use `when(...)`.
|
|
68
|
+
|
|
69
|
+
### Resource
|
|
70
|
+
|
|
71
|
+
`resource(name, { uri, title?, description?, mimeType?, fulfil })`. `fulfil` returns `{ contents: [{ uri, mimeType, text }] }`. Use a fixed URI for a constant document, or a `{var}` template whose variable arrives on `ctx.input`.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import { resource } from '@noodleseed/one';
|
|
75
|
+
|
|
76
|
+
// Fixed-URI resource: one constant document the model can read.
|
|
77
|
+
resource('changelog', {
|
|
78
|
+
uri: 'docs://changelog',
|
|
79
|
+
title: 'Changelog',
|
|
80
|
+
mimeType: 'text/markdown',
|
|
81
|
+
fulfil: () => ({
|
|
82
|
+
contents: [
|
|
83
|
+
{ uri: 'docs://changelog', mimeType: 'text/markdown', text: 'Changelog: 1.0.0 first release' },
|
|
84
|
+
],
|
|
85
|
+
}),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// {var} URI-template resource: the URI variable arrives on ctx.input (a symbolic ref).
|
|
89
|
+
resource('ticket', {
|
|
90
|
+
uri: 'tickets://{id}',
|
|
91
|
+
title: 'Support ticket',
|
|
92
|
+
mimeType: 'text/markdown',
|
|
93
|
+
fulfil: (ctx) => ({
|
|
94
|
+
contents: [
|
|
95
|
+
{ uri: `tickets://${ctx.input.id}`, mimeType: 'text/markdown', text: `Ticket ${ctx.input.id}` },
|
|
96
|
+
],
|
|
97
|
+
}),
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Prompt
|
|
102
|
+
|
|
103
|
+
`prompt(name, { title?, description?, arguments?, fulfil })`. `arguments` is a Zod object (each key becomes a `prompts/list` descriptor) or an explicit `[{ name, description?, required? }]` list. `fulfil` returns `{ messages: [{ role, content: { type: 'text', text } }] }`; supplied argument values arrive on `ctx.input`.
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { prompt, z } from '@noodleseed/one';
|
|
107
|
+
|
|
108
|
+
prompt('summarize_ticket', {
|
|
109
|
+
title: 'Summarize ticket',
|
|
110
|
+
description: 'Draft a short summary of a support ticket.',
|
|
111
|
+
// A Zod object: each key becomes a prompts/list descriptor (or pass [{ name, description?, required? }]).
|
|
112
|
+
arguments: z.object({
|
|
113
|
+
ticket_id: z.string().describe('Ticket to summarize'),
|
|
114
|
+
tone: z.enum(['concise', 'detailed']).default('concise'),
|
|
115
|
+
}),
|
|
116
|
+
// Argument values arrive on ctx.input; return the prompts/get messages shape.
|
|
117
|
+
fulfil: (ctx) => ({
|
|
118
|
+
messages: [
|
|
119
|
+
{
|
|
120
|
+
role: 'user',
|
|
121
|
+
content: {
|
|
122
|
+
type: 'text',
|
|
123
|
+
text: `Summarize ticket ${ctx.input.ticket_id} in a ${ctx.input.tone} tone.`,
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
}),
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Non-trivial tool: ctx connectors, annotations, visibility, async
|
|
132
|
+
|
|
133
|
+
`ctx` is `{ input, user, connectors }`. Bind connectors with `use` on the server, then call one inside `fulfil` to record a step. `annotations.readOnly()` / `annotations.action()` set the tool hints; `visibility` defaults to `['model', 'app']` — set `['app']` to hide a helper from the model. `fulfil` may be `async` (the compiler awaits it while recording).
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
import { annotations, connector, server, tool, z } from '@noodleseed/one';
|
|
137
|
+
|
|
138
|
+
// A tool-facing HTTP connector, bound to the server via `use`, reachable as ctx.connectors.crm.
|
|
139
|
+
const crm = connector('crm')
|
|
140
|
+
.version('1.0.0')
|
|
141
|
+
.http({
|
|
142
|
+
baseUrl: 'https://crm.example.com',
|
|
143
|
+
allowedOrigins: ['https://crm.example.com'],
|
|
144
|
+
operations: {
|
|
145
|
+
get_ticket: {
|
|
146
|
+
type: 'read',
|
|
147
|
+
method: 'GET',
|
|
148
|
+
path: '/tickets',
|
|
149
|
+
query: ['id'],
|
|
150
|
+
input: { id: { type: 'string', required: true } },
|
|
151
|
+
output: { subject: { type: 'string' }, status: { type: 'string' } },
|
|
152
|
+
response: { subject: '${response.subject}', status: '${response.status}' },
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
export default server('support', { title: 'Support', version: '1.0.0', use: { crm } }, [
|
|
158
|
+
tool('get_ticket', {
|
|
159
|
+
description: 'Fetch a support ticket by id.',
|
|
160
|
+
input: z.object({ id: z.string() }),
|
|
161
|
+
output: z.object({ subject: z.string(), status: z.string() }),
|
|
162
|
+
annotations: annotations.readOnly(), // read-only hint for hosts
|
|
163
|
+
visibility: ['model', 'app'], // default; use ['app'] to hide the tool from the model
|
|
164
|
+
// ctx is { input, user, connectors }. A connector call records one flow step (a Ref) —
|
|
165
|
+
// recording is not execution, so never branch on the result with native if (use when).
|
|
166
|
+
fulfil: ({ input, connectors }) => {
|
|
167
|
+
const found = connectors.crm.get_ticket({ id: input.id });
|
|
168
|
+
return { subject: found.subject, status: found.status };
|
|
169
|
+
},
|
|
170
|
+
}),
|
|
171
|
+
tool('echo', {
|
|
172
|
+
description: 'Echo text back.',
|
|
173
|
+
input: z.object({ text: z.string() }),
|
|
174
|
+
output: z.object({ echo: z.string() }),
|
|
175
|
+
annotations: annotations.action(), // mutating / world-affecting hint
|
|
176
|
+
// fulfil may be async — the compiler awaits it while recording the flow.
|
|
177
|
+
fulfil: async ({ input }) => ({ echo: input.text }),
|
|
178
|
+
}),
|
|
179
|
+
]);
|
|
180
|
+
```
|