@nanobpm/nano-workforce 0.108.0 → 0.110.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.
@@ -0,0 +1,36 @@
1
+ // GET /app/api/agent/skill → operationId `getAgentSkill` (ADR 0058/0059 OpenAPI surface, base
2
+ // /app/api). Serves the portable operator *skill* (SKILL.md) an agent runtime loads on demand: a
3
+ // thin bootstrap that resolves which instance to drive and then fetches the live operator guide
4
+ // (GET /app/api/agent). Companion to getAgentInstructions.
5
+ //
6
+ // The runtime serializes an operation body as JSON, so the markdown skill is returned as the
7
+ // `skill` string field (alongside the app version + the base URL it was fetched from). Any
8
+ // `__BASE__` example is rewritten to THIS instance's control-API base (derived from the request).
9
+ //
10
+ // Read-only. The optional shared-secret guard mirrors /version and /agent: enforced HERE only when
11
+ // NANO_PR_WEBHOOK_SECRET is set (the runtime does not enforce OpenAPI `security`).
12
+
13
+ import { renderAgentSkill } from "../app/agentSkill.ts";
14
+ import { resolveApiBase } from "../app/resolveApiBase.ts";
15
+ import { buildVersionInfo, envVar } from "../app/version.ts";
16
+ import { defineOperation } from "../nano-generated/operations.ts";
17
+
18
+ const SECRET = envVar("NANO_PR_WEBHOOK_SECRET") ?? "";
19
+
20
+ export default defineOperation("getAgentSkill", ({ req }, app) => {
21
+ if (SECRET && req.headers.get("x-hook-secret") !== SECRET) {
22
+ app.log.warn("getAgentSkill rejected: missing/invalid shared secret");
23
+ return { status: 401, body: { error: "unauthorized" } };
24
+ }
25
+ const baseUrl = resolveApiBase(req, "agent/skill");
26
+ return {
27
+ status: 200,
28
+ body: {
29
+ format: "markdown",
30
+ appVersion: buildVersionInfo().version,
31
+ generatedAt: new Date().toISOString(),
32
+ baseUrl,
33
+ skill: renderAgentSkill(baseUrl),
34
+ },
35
+ };
36
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanobpm/nano-workforce",
3
- "version": "0.108.0",
3
+ "version": "0.110.0",
4
4
  "description": "Nano Workforce — an Agent Graph Orchestration application for Agentic SDLC: durable BPMN processes that coordinate a graph of AI agents across the software delivery lifecycle.",
5
5
  "type": "module",
6
6
  "main": "main.ts",
@@ -73,20 +73,6 @@
73
73
  "variant": "sub"
74
74
  }
75
75
  },
76
- {
77
- "type": "button",
78
- "id": "agent-instructions",
79
- "props": {
80
- "label": "\ud83e\udd16 Agent Instructions",
81
- "variant": "ghost",
82
- "modal": {
83
- "title": "Point your agent at Nano Workforce",
84
- "description": "Copy this prompt and paste it into your coding agent (Copilot, Claude, etc.). It tells the agent to read this workforce's live operator guide, then help you drive and debug it.",
85
- "copyLabel": "Copy prompt",
86
- "copyText": "You are helping me operate a running Nano Workforce instance \u2014 a durable orchestration app that drives pull requests to review convergence against an automated reviewer, merges them, and can take a whole issue and plan \u2192 implement \u2192 converge it across a fleet of coding agents.\n\nFirst, fetch and read its live operator guide. It tells you how to submit PRs and epics for convergence (including whether to go all the way to merge or stop at review consensus), how to find engine instances and relate them to PRs via the Nano/Camunda-8 REST API, how to inspect the models and prompts, and how to help me untangle escalations:\n\n curl -sS {{appBase}}app/api/agent\n\nIf this instance is secured with a shared secret (NANO_PR_WEBHOOK_SECRET), add its value as an x-hook-secret header, otherwise the request returns 401:\n\n curl -sS -H \"x-hook-secret: <secret>\" {{appBase}}app/api/agent\n\nThen follow that guide to help me drive and debug this workforce. If you find a bug or a stuck process, the guide explains how to raise an issue or a PR against nanobpm/nano-workforce."
87
- }
88
- }
89
- },
90
76
  {
91
77
  "type": "actionForm",
92
78
  "id": "submit",
@@ -70,6 +70,20 @@
70
70
  "variant": "sub"
71
71
  }
72
72
  },
73
+ {
74
+ "type": "button",
75
+ "id": "agent-instructions",
76
+ "props": {
77
+ "label": "\ud83e\udd16 Agent Instructions",
78
+ "variant": "ghost",
79
+ "modal": {
80
+ "title": "Point your agent at Nano Workforce",
81
+ "description": "Copy this prompt and paste it into your coding agent (Copilot, Claude, etc.). It tells the agent to load this workforce's operator skill from this instance, then help you drive and debug it.",
82
+ "copyLabel": "Copy prompt",
83
+ "copyText": "Load the Nano Workforce operator skill from this running instance and then help me drive and debug my workforce \u2014 a durable orchestration app that drives pull requests to review convergence against an automated reviewer, merges them, and can take a whole issue and plan \u2192 implement \u2192 converge it across a fleet of coding agents.\n\nThis is the instance to operate; its control-API base is {{appBase}}app/api. Fetch the skill and follow it (the response is JSON with a `skill` markdown field):\n\n curl -sS {{appBase}}app/api/agent/skill\n\nIf this instance is secured with a shared secret (NANO_PR_WEBHOOK_SECRET), add its value as an x-hook-secret header, otherwise the request returns 401:\n\n curl -sS -H \"x-hook-secret: <secret>\" {{appBase}}app/api/agent/skill\n\nThe skill is a thin bootstrap: it has you fetch this instance's live operator guide (at {{appBase}}app/api/agent) and then drive the workforce \u2014 submit PRs and epics for convergence, answer escalations, and debug stuck processes. If you find a bug or a stuck process, the guide explains how to raise an issue or a PR against nanobpm/nano-workforce."
84
+ }
85
+ }
86
+ },
73
87
  {
74
88
  "type": "dataGrid",
75
89
  "id": "overview-prs",
@@ -0,0 +1,50 @@
1
+ # Agent skills
2
+
3
+ Portable agent skills that ship with Nano Workforce. A skill is a `SKILL.md` with
4
+ YAML frontmatter (`name`, `description`) that an agent runtime (Copilot CLI, Claude)
5
+ loads on demand when its `description` matches the task.
6
+
7
+ ## `nano-workforce`
8
+
9
+ A **thin bootstrap** that teaches any agent to operate a running Nano Workforce
10
+ instance: it resolves the instance base URL and fetches the instance's *live*
11
+ operator guide (`GET /app/api/agent`), then follows it. It deliberately holds no
12
+ endpoint detail of its own — the live, version-matched guide is the source of truth.
13
+
14
+ ### Install
15
+
16
+ Copy or symlink the skill into your agent's skills directory. For Copilot CLI:
17
+
18
+ ```bash
19
+ # symlink so it tracks this repo
20
+ ln -s "$(pwd)/skills/nano-workforce" ~/.copilot/skills/nano-workforce
21
+ # …or copy it
22
+ cp -r skills/nano-workforce ~/.copilot/skills/nano-workforce
23
+ ```
24
+
25
+ Then, from an agent session against your instance:
26
+
27
+ ```
28
+ Load the nano-workforce skill and drive my workforce.
29
+ ```
30
+
31
+ Set `NANO_WORKFORCE_URL` (and `NANO_PR_WEBHOOK_SECRET`, if your instance guards the
32
+ agent endpoints) so the bootstrap can reach your instance without prompting.
33
+
34
+ ### Multiple instances
35
+
36
+ If you run more than one instance (a local copy, one on the LAN, a tunnel when
37
+ you're off-LAN), register them by name so the skill can offer a choice and probe
38
+ which is live. Set `NANO_WORKFORCE_INSTANCES`, or write
39
+ `~/.config/nano-workforce/instances.json`:
40
+
41
+ ```json
42
+ {
43
+ "local": "http://localhost:3000/app/api",
44
+ "merlin": "http://merlin.local:3000/app/api",
45
+ "remote": "https://<subdomain>.ngrok.app/app/api"
46
+ }
47
+ ```
48
+
49
+ Then just say *"drive merlin"* — or let the skill probe reachability and ask which
50
+ to use (off the LAN, `merlin.local` won't resolve, so it steers you to `remote`).
@@ -0,0 +1,126 @@
1
+ ---
2
+ name: nano-workforce
3
+ description: Drive and debug a running Nano Workforce instance — submit PRs for review convergence, submit issues/epics for plan→implement→converge, submit agent-authored delivery graphs (ADR 0005), answer escalations, and unstick stuck instances. Use when the user asks to operate, drive, submit work to, or debug their Nano Workforce.
4
+ ---
5
+
6
+ # Nano Workforce operator skill
7
+
8
+ Nano Workforce (nwf) is a durable orchestration app that drives pull requests to
9
+ **review convergence** and merges them, takes whole issues and **plans →
10
+ implements → converges** them across a fleet of coding agents, and runs
11
+ **agent-authored delivery graphs** (heterogeneous cross-repo, human-in-the-loop
12
+ DAGs — ADR 0005).
13
+
14
+ **This skill is a thin bootstrap by design.** It does not describe the endpoints.
15
+ Every running nwf instance serves its own operator guide, *live*, keyed to that
16
+ instance's URLs and matched to its deployed version. Your job is to fetch that
17
+ guide and follow it — never to work from a cached copy, which drifts across
18
+ versions and instances.
19
+
20
+ ## 1. Confirm which instance you are driving — always
21
+
22
+ A user typically runs **several** Nano Workforce instances — e.g. a local dev copy,
23
+ one on the LAN (`http://merlin.local:3000/app/api`), and a public tunnel
24
+ (an ngrok URL) when off the LAN. Every action here is **side-effecting** —
25
+ submitting work, answering escalations, merging PRs — so targeting the wrong
26
+ instance is a real mistake, not a harmless one. **Never silently default to a
27
+ base URL.**
28
+
29
+ ### Sources of candidate instances
30
+
31
+ Gather candidates from, in order:
32
+
33
+ 1. **A named-instance registry** the user maintains — first of these that exists:
34
+ `$NANO_WORKFORCE_INSTANCES` (JSON object of `name → base URL`), or
35
+ `~/.config/nano-workforce/instances.json` (same shape). Example:
36
+
37
+ ```json
38
+ { "local": "http://localhost:3000/app/api",
39
+ "merlin": "http://merlin.local:3000/app/api",
40
+ "remote": "https://<subdomain>.ngrok.app/app/api" }
41
+ ```
42
+
43
+ 2. `$NANO_WORKFORCE_URL`, if set (a single default; accept as-is, append `/app/api`
44
+ only if it is a bare origin).
45
+ 3. Any URL the user names in the conversation.
46
+ 4. Local fallback: `http://localhost:3000/app/api` (port `PR_REVIEW_PORT`, default `3000`).
47
+
48
+ ### Choosing
49
+
50
+ - If the user **named an instance** (by name from the registry, or by URL), use it.
51
+ - Otherwise, **probe the candidates for reachability** and ask the user which to
52
+ use, offering the candidates as choices and marking which are live. Reachability
53
+ disambiguates the common case — off the LAN, `merlin.local` won't resolve, so the
54
+ tunnel instance is the live one:
55
+
56
+ ```bash
57
+ # For each candidate base, a fast liveness + identity check:
58
+ curl -sS --max-time 3 \
59
+ ${NANO_PR_WEBHOOK_SECRET:+-H "x-hook-secret: $NANO_PR_WEBHOOK_SECRET"} \
60
+ "$BASE/version" | jq '{appVersion, gitSha, uptimeSeconds}'
61
+ ```
62
+
63
+ - Only skip the question when exactly **one** candidate exists and is reachable —
64
+ and even then, **name the instance you're about to drive** before acting.
65
+
66
+ Some instances guard the agent endpoints with a shared secret. If the user has
67
+ `$NANO_PR_WEBHOOK_SECRET` set, send it as `x-hook-secret` on every request below.
68
+
69
+ ## 2. Fetch the live guide — this is your real playbook
70
+
71
+ ```bash
72
+ curl -sS ${NANO_PR_WEBHOOK_SECRET:+-H "x-hook-secret: $NANO_PR_WEBHOOK_SECRET"} \
73
+ "$BASE/agent" | jq -r '.instructions'
74
+ ```
75
+
76
+ `GET /app/api/agent` (`getAgentInstructions`) returns
77
+ `{ format, appVersion, generatedAt, baseUrl, engineBase, instructions }`. The
78
+ `instructions` markdown is the authoritative, version-matched operator guide, with
79
+ every example already keyed to this instance's `baseUrl`/`engineBase`. Read it in
80
+ full and follow it for everything that follows — orientation, submitting work,
81
+ answering escalations, and debugging.
82
+
83
+ **Always re-fetch the guide at the start of a session.** It is the source of truth;
84
+ this skill only tells you how to find it.
85
+
86
+ ## 3. Orient before acting
87
+
88
+ The guide's first steps confirm what is live and what is in flight:
89
+
90
+ ```bash
91
+ curl -sS "$BASE/version" | jq # app/urban version, git sha, uptime
92
+ curl -sS "$BASE/status" | jq # every PR/instance in flight + open escalations
93
+ ```
94
+
95
+ `/status` is the primary situational-awareness endpoint — check it before you
96
+ submit or unstick anything.
97
+
98
+ ## 4. What you can drive (all detailed in the live guide)
99
+
100
+ - **Submit a PR** for review convergence — `POST $BASE/actions/start/convergence-loop`.
101
+ - **Submit an issue/epic** for plan → implement → converge across the fleet —
102
+ `POST $BASE/actions/start/plan-fanout`.
103
+ - **Submit a delivery graph** (ADR 0005) — propose → preview → approve → dispatch.
104
+ Compile/preview is a pure, side-effect-free tool; only the start door dispatches.
105
+ The live guide documents the exact operations once the instance exposes them.
106
+ - **Answer an escalation** (a durable user task the workforce parked on) —
107
+ `POST $BASE/actions/complete-user-task`, or the agent hook
108
+ `POST $BASE/hooks/agent-complete` (`agentCompleteEscalation`).
109
+ - **Debug**: relate an in-flight PR to its engine process instance via `processKey`
110
+ from `/status`, then use the engine REST base (`engineBase` from the guide) to
111
+ inspect and unstick it.
112
+
113
+ ## Principles
114
+
115
+ - **Discover, don't declare.** Prefer the live guide and live `/status` over any
116
+ assumption baked into this file. If this skill and the guide disagree, the guide
117
+ wins.
118
+ - **Confirm the target instance.** Never run a side-effecting call against an
119
+ assumed base URL. Know — and when ambiguous, ask — which instance you're driving.
120
+ - **Preview before dispatch.** For delivery graphs and any bulk action, use the
121
+ pure preview/validate path first and show the user the plan before the
122
+ side-effecting start call.
123
+ - **Idempotency.** Submissions carry dedupe keys; re-submitting the same work must
124
+ not double-dispatch. The guide documents the keys — honour them.
125
+ - **Escalations are for humans.** When the workforce parks on a human node, surface
126
+ it to the user with options; don't silently auto-answer design/product decisions.