@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.
- package/CHANGELOG.md +14 -0
- package/app/agentSkill.ts +54 -0
- package/app/contracts.ts +9 -0
- package/app/deliveryGraph.test.ts +357 -0
- package/app/deliveryGraph.ts +463 -0
- package/app/resolveApiBase.test.ts +43 -0
- package/app/resolveApiBase.ts +28 -0
- package/docs/adr/0005-agent-authored-delivery-graphs.md +221 -0
- package/openapi.yaml +298 -0
- package/operations/getAgentInstructions.ts +2 -16
- package/operations/getAgentSkill.test.ts +72 -0
- package/operations/getAgentSkill.ts +36 -0
- package/package.json +1 -1
- package/pages/home.page.json +0 -14
- package/pages/overview.page.json +14 -0
- package/skills/README.md +50 -0
- package/skills/nano-workforce/SKILL.md +126 -0
|
@@ -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.
|
|
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",
|
package/pages/home.page.json
CHANGED
|
@@ -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",
|
package/pages/overview.page.json
CHANGED
|
@@ -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",
|
package/skills/README.md
ADDED
|
@@ -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.
|