@delorenj/pjangler 1.2.6 → 1.2.9

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.
Files changed (27) hide show
  1. package/dist/index.js +54 -16
  2. package/dist/mcp-server.js +66 -17
  3. package/package.json +1 -1
  4. package/templates/commonproject/AGENTS.md +3 -3
  5. package/templates/commonproject/README.md +12 -11
  6. package/templates/commonproject/copier.yml +24 -8
  7. package/templates/commonproject/mise.toml +3 -3
  8. package/templates/commonproject/template/.project.json.jinja +13 -6
  9. package/templates/hermes-agent/README.md +8 -8
  10. package/templates/hermes-agent/copier.yml +3 -4
  11. package/templates/hermes-agent/docs/architecture.md +4 -4
  12. package/templates/hermes-agent/docs/operations.md +2 -2
  13. package/templates/hermes-agent/docs/sentinel/README.md +6 -8
  14. package/templates/hermes-agent/docs/sentinel/architecture.md +2 -1
  15. package/templates/hermes-agent/docs/sentinel/development.md +13 -12
  16. package/templates/hermes-agent/docs/sentinel/providers.md +12 -32
  17. package/templates/hermes-agent/install-local.sh +6 -13
  18. package/templates/hermes-agent/template/.scripts/42-ticket-provider.sh +14 -37
  19. package/templates/hermes-agent/template/.scripts/70-systemd.sh +1 -0
  20. package/templates/hermes-agent/template/.scripts/lib/ticket-provider.sh +6 -2
  21. package/templates/hermes-agent/template/.scripts/sentinel/docs/autonomous-delegated-review.md +2 -2
  22. package/templates/hermes-agent/template/.scripts/sentinel/docs/continuous-ticket-orchestration.md +1 -1
  23. package/templates/hermes-agent/template/.scripts/sentinel.prompt.md.jinja +5 -7
  24. package/templates/hermes-agent/template/SOUL.md.jinja +8 -7
  25. package/templates/hermes-agent/template/role.yaml.jinja +3 -6
  26. package/templates/hermes-agent/template/.scripts/40-plane.sh +0 -51
  27. package/templates/hermes-agent/template/.scripts/providers/linear.sh +0 -176
@@ -12,13 +12,13 @@
12
12
  # 1. Renders agents/hermes/<role>/{role.yaml, SOUL.md, hermes, .scripts/}
13
13
  # 2. Creates a per-agent runtime repo gh:delorenj/agent-hm-<repo>-<role>
14
14
  # 3. Submodules it at agents/hermes/<role>/runtime/ (this is HERMES_HOME)
15
- # 4. Creates a Plane project in 33god workspace
15
+ # 4. Creates or binds the configured ticket board
16
16
  # 6. Prompts for a BotFather Telegram token, stores in runtime/.env
17
17
  # 7. Installs a Bloodbank consumer + heartbeat timer (reconcile + checkpoint)
18
18
  # 8. Appends to ~/.hermes/agents-registry.yaml
19
19
  #
20
- # Environment-specific defaults (Hermes binary path, runtime repo owner, Plane
21
- # workspace/URL, NATS endpoint, skills dir, …) are NOT hardcoded — they live in
20
+ # Environment-specific defaults (Hermes binary path, runtime repo owner, ticket
21
+ # provider defaults, NATS endpoint, skills dir, …) are NOT hardcoded — they live in
22
22
  # ~/.config/hermes-agent-template/config.toml, seeded from config.example.toml on
23
23
  # first run. Edit that file to retarget the template for a different machine/user.
24
24
 
@@ -59,7 +59,6 @@ ticket_provider:
59
59
  help: "Ticket system this agent's board lives in"
60
60
  default: plane
61
61
  choices:
62
- "Linear": linear
63
62
  "Plane": plane
64
63
  "Trello": trello
65
64
 
@@ -92,11 +92,11 @@ happen to share a token, the second one's startup fails fast. The N×M cost
92
92
  (N BotFather sessions per fleet) is the price we accept for zero custom
93
93
  routing code.
94
94
 
95
- ## One Plane project per agent
95
+ ## One Ticket Board Per Repo
96
96
 
97
- A Plane "project" is the natural unit of work isolation. Mixing agents into a
98
- shared project would conflate decisions and break filters. 1:1 also makes
99
- archive-on-retire clean.
97
+ The configured ticket board is the natural unit of work isolation. The PM owns
98
+ one board per repo and routes worker agents through that shared source of truth,
99
+ so decisions, filters, and review state stay coherent.
100
100
 
101
101
  ## Bloodbank wiring
102
102
 
@@ -29,7 +29,7 @@ invocations).
29
29
  | 10 hermes profile | `hermes profile create <repo>-<role> --clone --no-alias` + mirror skills/plugins/hooks from default + symlink canonical runtime skills (`delonet-conventions`, `delonet-dotenv`, `hermes-pm-template-maintenance`, `hindsight`, `subagent-driven-development`) from `/home/delorenj/.agents/skills`; PM roles also seed `VOX_URL` in profile `.env` | n/a |
30
30
  | 20 runtime repo | Create gh:delorenj/agent-hm-<repo>-<role> (private), push scaffold from role-local `.runtime-scaffold/`, submodule-add into ./runtime/, symlink ~/.hermes/profiles/<id> → runtime; PM roles also link the Voxxy plugin and set `tts.provider: voxxy` | `SKIP_RUNTIME_REPO=1` |
31
31
  | 30 telegram | Capture BotFather token, write to runtime/.env, enable hermes-telegram toolset | `SKIP_TELEGRAM=1` |
32
- | 40 plane | Create Plane project in 33god workspace (1:1 with agent), patch identifier into role.yaml | `SKIP_PLANE=1` |
32
+ | 42 ticket provider | Create or bind the configured ticket board, patch identifier into role.yaml | `SKIP_PLANE=1` |
33
33
  | 60 bloodbank | Install consumer (renders from scaffold w/ agent values), health-check NATS, install nats-py via uv if missing | `SKIP_BLOODBANK=1` |
34
34
  | 70 systemd | Install user units: gateway, consumer, heartbeat timer (board-reconciliation sentinel pass + gated runtime checkpoint, one tick) | `SKIP_SYSTEMD=1` |
35
35
  | 80 registry | Append entry to ~/.hermes/agents-registry.yaml | n/a |
@@ -187,7 +187,7 @@ systemctl --user disable --now hermes-${AGENT}-heartbeat.timer
187
187
  # that's what you want!)
188
188
  hermes profile delete ${AGENT}
189
189
 
190
- # 3. Archive Plane project (Plane UI or API)
190
+ # 3. Archive the ticket board if the provider supports archival
191
191
  PROJECT_ID=$(python3 -c "import yaml,pathlib; print(yaml.safe_load(pathlib.Path.home().joinpath('.hermes/agents-registry.yaml').read_text())['agents']['${AGENT}']['plane']['project_id'])")
192
192
  curl -X POST "https://plane.delo.sh/api/v1/workspaces/33god/projects/${PROJECT_ID}/archive/" \
193
193
  -H "X-API-Key: ${PLANE_33GOD_API_KEY}"
@@ -26,7 +26,7 @@ that does the board-reconciliation pass and then a gated runtime checkpoint
26
26
  `.scripts/sentinel/`.
27
27
 
28
28
  It talks to the ticket board through a pluggable adapter, so the same engine
29
- runs on Linear, Plane, or Trello. The engine lives once in this template (the
29
+ runs on Plane or Trello. The engine lives once in this template (the
30
30
  single source of truth) and propagates to every deployment with
31
31
  `copier update`.
32
32
 
@@ -37,8 +37,6 @@ The following is true as of June 1, 2026.
37
37
  - The engine, the provider abstraction, and the autonomous adversarial-review
38
38
  enforcement are built, syntax-clean, and validated offline with a mock
39
39
  provider.
40
- - The **Linear** adapter is verified live against a real board (a real
41
- `DEL` team: `resolve`, `list_issues` returning 93 issues, and `get_issue`).
42
40
  - The **Plane** adapter is verified live against a real workspace
43
41
  (`resolve`, `list_issues`, `get_issue`, `comment`, and a
44
42
  `transition` to `completed` on a disposable issue).
@@ -54,7 +52,7 @@ For a local, single-machine install (no GitHub runtime repo, no Telegram, no
54
52
  NATS), use the one-command bootstrap. From inside the target project:
55
53
 
56
54
  ```bash
57
- export PLANE_API_KEY=<key> # or LINEAR_API_KEY / TRELLO_KEY + TRELLO_TOKEN
55
+ export PLANE_API_KEY=<key> # or TRELLO_KEY + TRELLO_TOKEN
58
56
  curl -fsSL https://raw.githubusercontent.com/delorenj/hermes-agent-template/main/install-local.sh | sh
59
57
  ```
60
58
 
@@ -66,7 +64,7 @@ macOS). See [Development guide: local install](development.md#local-install-one-
66
64
  <!-- prettier-ignore -->
67
65
  > [!IMPORTANT]
68
66
  > Full (non-local) provisioning is outward-facing. It can create a GitHub
69
- > runtime repo, a Telegram bot, and a Plane project, and the Telegram step is
67
+ > runtime repo, a Telegram bot, and a ticket board, and the Telegram step is
70
68
  > interactive. Use `install-local.sh` or the `SKIP_*` flags described in
71
69
  > [Development guide:
72
70
  > provisioning](development.md#provisioning-the-pm-manual) for local or lean
@@ -81,7 +79,7 @@ All paths are relative to the repository root.
81
79
  | `copier.yml` | Questions (`role`, `ticket_provider`) and the `_tasks` provisioning chain. |
82
80
  | `template/role.yaml.jinja` | The rendered role manifest, including the `ticket_provider` binding and the `reconcile` knobs (`grace_hours`, `auto_review`). |
83
81
  | `template/.scripts/lib/ticket-provider.sh` | The adapter dispatcher (`tp`). The engine's only seam to a ticket system. |
84
- | `template/.scripts/providers/{linear,plane,trello}.sh` | The provider adapters. |
82
+ | `template/.scripts/providers/{plane,trello}.sh` | The provider adapters. |
85
83
  | `template/.scripts/42-ticket-provider.sh` | Provisioning step that resolves or creates the board. |
86
84
  | `template/.scripts/70-systemd.sh` | Provisioning step that installs the gateway, consumer, and the fused `heartbeat` timer (board-reconciliation sentinel pass + gated runtime checkpoint). |
87
85
  | `install-local.sh` | One-command local install (no cloud, macOS + Linux). |
@@ -109,8 +107,8 @@ the agent to read at run time. Keep the two in sync when behavior changes.
109
107
 
110
108
  The highest-value open work, in order:
111
109
 
112
- 1. Live-verify the **Trello** adapter against a real board (Linear and Plane are
113
- done). See [Providers: verifying an
110
+ 1. Live-verify the **Trello** adapter against a real board (Plane is done).
111
+ See [Providers: verifying an
114
112
  adapter](providers.md#verifying-an-adapter-against-a-live-board).
115
113
  2. Confirm `install-local.sh` on a real macOS machine. The Linux path and the
116
114
  Plane adapter are verified; the macOS `launchd` agent and `mkdir` lock get
@@ -71,7 +71,8 @@ function, `tp`, that dispatches to one provider implementation under
71
71
  through the `ticket_provider` question and recorded in `role.yaml` under
72
72
  `ticket_provider.name`.
73
73
 
74
- This is what lets one engine serve three back ends: Trello, Plane, and Linear.
74
+ This is what lets one engine serve the supported ticket back ends: Plane and
75
+ Trello.
75
76
  For the full contract and the per-provider details, see
76
77
  [Providers](providers.md).
77
78
 
@@ -112,7 +112,7 @@ repository root instead of driving Copier by hand. From inside the target
112
112
  project:
113
113
 
114
114
  ```bash
115
- export PLANE_API_KEY=<key> # or LINEAR_API_KEY / TRELLO_KEY + TRELLO_TOKEN
115
+ export PLANE_API_KEY=<key> # or TRELLO_KEY + TRELLO_TOKEN
116
116
  curl -fsSL https://raw.githubusercontent.com/delorenj/hermes-agent-template/main/install-local.sh | sh
117
117
  ```
118
118
 
@@ -133,8 +133,8 @@ The script:
133
133
  7. smoke-tests the board connection through the adapter.
134
134
 
135
135
  Useful environment overrides (skip the prompts): `HAT_REPO`, `HAT_PROVIDER`,
136
- `HAT_ROLES`, `HAT_PLANE_WORKSPACE`, `HAT_PLANE_PROJECT`, `HAT_LINEAR_TEAM`,
137
- `HAT_TRELLO_BOARD`, and `HAT_DRY_RUN=1` to preview without changing anything.
136
+ `HAT_ROLES`, `HAT_PLANE_WORKSPACE`, `HAT_PLANE_PROJECT`, `HAT_TRELLO_BOARD`,
137
+ and `HAT_DRY_RUN=1` to preview without changing anything.
138
138
 
139
139
  This local path does not wire Telegram or email. Those are convenience layers in
140
140
  the `pjangler` provisioner, not requirements for a working agent — talk to the
@@ -151,7 +151,7 @@ cd /path/to/your-project
151
151
  copier copy gh:delorenj/hermes-agent-template ./agents/hermes/pm \
152
152
  --data role=pm \
153
153
  --data target_repo=<repo> \
154
- --data ticket_provider=<linear|plane|trello>
154
+ --data ticket_provider=<plane|trello>
155
155
  ```
156
156
 
157
157
  The `_tasks` chain in `copier.yml` runs the numbered provisioning scripts in
@@ -162,7 +162,7 @@ order. Several of them reach outside the repository.
162
162
  > Full provisioning is outward-facing and partly interactive.
163
163
  > `20-runtime-repo.sh` creates a private GitHub repo with `gh repo create`,
164
164
  > `30-telegram.sh` prompts for a BotFather token and blocks waiting for input,
165
- > and `42-ticket-provider.sh` can create a Plane project. Don't run full
165
+ > and `42-ticket-provider.sh` can create a ticket board. Don't run full
166
166
  > provisioning unattended.
167
167
 
168
168
  Use the `SKIP_*` environment flags for a local or lean install. Each numbered
@@ -172,7 +172,7 @@ script checks its flag and skips cleanly.
172
172
  | --- | --- |
173
173
  | `SKIP_TELEGRAM` | The interactive BotFather token step. |
174
174
  | `SKIP_RUNTIME_REPO` | Creating the GitHub runtime repo. |
175
- | `SKIP_PLANE` | Creating a Plane project. |
175
+ | `SKIP_PLANE` | Creating or linking the ticket board. |
176
176
  | `SKIP_BLOODBANK` | Installing the BloodBank consumer. |
177
177
  | `SKIP_SYSTEMD` | Installing `systemd` units (gateway, consumer, heartbeat timer). |
178
178
 
@@ -181,13 +181,14 @@ For example, a local install that creates no cloud resources:
181
181
  ```bash
182
182
  SKIP_TELEGRAM=1 SKIP_RUNTIME_REPO=1 SKIP_PLANE=1 SKIP_BLOODBANK=1 \
183
183
  copier copy gh:delorenj/hermes-agent-template ./agents/hermes/pm \
184
- --data role=pm --data target_repo=<repo> --data ticket_provider=linear
184
+ --data role=pm --data target_repo=<repo> --data ticket_provider=trello
185
185
  ```
186
186
 
187
187
  After provisioning, set the board binding in
188
- `agents/hermes/pm/role.yaml`. For Linear, set `ticket_provider.team`
189
- to the team key. Make the provider key available to the heartbeat's environment:
190
- on Linux through a `systemd` `EnvironmentFile` (for example
188
+ `agents/hermes/pm/role.yaml`. For Trello, set `ticket_provider.board` to the
189
+ board id; for Plane, set `ticket_provider.workspace` and `ticket_provider.project`.
190
+ Make the provider key available to the heartbeat's environment: on Linux through
191
+ a `systemd` `EnvironmentFile` (for example
191
192
  `~/.hermes/<agent_id>.env`); on macOS the `launchd` agent sources that same
192
193
  per-agent env file, so write the key there.
193
194
 
@@ -256,8 +257,8 @@ These cost real debugging time. Watch for them.
256
257
 
257
258
  The following work is open for the incoming agent, roughly in priority order.
258
259
 
259
- 1. **Live-verify the Trello adapter.** Linear and Plane are verified live
260
- (Plane includes `transition` and `comment`). Trello is implemented against
260
+ 1. **Live-verify the Trello adapter.** Plane is verified live
261
+ (including `transition` and `comment`). Trello is implemented against
261
262
  the contract but unverified. Follow [Providers: verifying an
262
263
  adapter](providers.md#verifying-an-adapter-against-a-live-board) with Trello
263
264
  credentials, and fix any endpoint or field mismatches.
@@ -1,7 +1,7 @@
1
1
  # Provider adapters
2
2
 
3
3
  This guide is the reference for the ticket-provider abstraction: the contract
4
- every adapter implements, the three adapters that ship today, and a
4
+ every adapter implements, the two adapters that ship today, and a
5
5
  step-by-step process for adding a new provider or verifying an existing one
6
6
  against a live board. Read [Architecture](architecture.md) first for how the
7
7
  adapter fits into the engine.
@@ -43,12 +43,8 @@ maps each to its back end's concrete state.
43
43
 
44
44
  ## The adapters that ship today
45
45
 
46
- The repository includes three adapters with different verification status.
46
+ The repository includes two supported adapters with different verification status.
47
47
 
48
- - **Linear** (`providers/linear.sh`) is the reference implementation. It uses
49
- the Linear GraphQL API. It's verified live against a real board. Linear's
50
- `issue(id:)` field accepts both the UUID and the human identifier (for
51
- example, `DEL-42`), so the engine can pass identifiers through.
52
48
  - **Plane** (`providers/plane.sh`) uses the Plane REST API with `X-API-Key`
53
49
  authentication. A Plane project maps to the board, a cycle maps to the
54
50
  milestone, and `state.group` maps to the state type. It's verified live. Note
@@ -64,21 +60,6 @@ The repository includes three adapters with different verification status.
64
60
 
65
61
  Set credentials in the environment and the board binding in `role.yaml`.
66
62
 
67
- <details>
68
- <summary>Linear</summary>
69
-
70
- - Credentials: `LINEAR_API_KEY`.
71
- - Binding:
72
-
73
- ```yaml
74
- ticket_provider:
75
- name: linear
76
- team: DEL # Linear team key
77
- project: "" # optional, scopes milestone and issue queries
78
- ```
79
-
80
- </details>
81
-
82
63
  <details>
83
64
  <summary>Plane</summary>
84
65
 
@@ -114,8 +95,9 @@ Set credentials in the environment and the board binding in `role.yaml`.
114
95
 
115
96
  To add a fourth provider, for example GitHub Issues or Jira, follow these steps.
116
97
 
117
- 1. Create `template/.scripts/providers/<name>.sh`. Start from `linear.sh` if the
118
- back end uses GraphQL, or `plane.sh` if it uses REST with a single API key.
98
+ 1. Create `template/.scripts/providers/<name>.sh`. Start from `plane.sh` if it
99
+ uses REST with a single API key, or `trello.sh` if it has a board/list/card
100
+ model.
119
101
  2. Implement every operation in [the contract](#the-contract). Return the exact
120
102
  JSON shapes shown in the table. Map your back end's states to the five
121
103
  normalized states.
@@ -127,8 +109,7 @@ To add a fourth provider, for example GitHub Issues or Jira, follow these steps.
127
109
  5. Extend `template/role.yaml.jinja` with a provider-specific binding block
128
110
  under the `{% if ticket_provider == '<name>' %}` branch.
129
111
  6. Teach `42-ticket-provider.sh` how to resolve or create the board for your
130
- provider, if it differs from the existing `linear`, `plane`, and `trello`
131
- cases.
112
+ provider, if it differs from the existing `plane` and `trello` cases.
132
113
  7. Validate and verify with the steps below.
133
114
 
134
115
  <!-- prettier-ignore -->
@@ -158,7 +139,7 @@ Before you touch a live board, confirm the adapter parses and fails cleanly.
158
139
  exit, with no Python traceback:
159
140
 
160
141
  ```bash
161
- ( unset LINEAR_API_KEY; sh template/.scripts/providers/linear.sh resolve )
142
+ ( unset PLANE_API_KEY; sh template/.scripts/providers/plane.sh resolve )
162
143
  ```
163
144
 
164
145
  ## Verifying an adapter against a live board
@@ -169,15 +150,15 @@ never closes or modifies a ticket, so it's safe to run.
169
150
 
170
151
  ```bash
171
152
  # 1. Load the credential into the environment only (never print it).
172
- export LINEAR_API_KEY="$(grep -E '^(export )?LINEAR_API_KEY=' \
173
- ~/.hermes/<agent>.env | head -1 | sed -E 's/^(export )?LINEAR_API_KEY=//; s/^"//; s/"$//')"
153
+ export PLANE_API_KEY="$(grep -E '^(export )?PLANE_API_KEY=' \
154
+ ~/.hermes/<agent>.env | head -1 | sed -E 's/^(export )?PLANE_API_KEY=//; s/^"//; s/"$//')"
174
155
 
175
156
  # 2. Stage a role directory bound to the real board.
176
157
  T=$(mktemp -d); RD="$T/agents/hermes/pm"
177
158
  mkdir -p "$RD/.scripts/lib" "$RD/.scripts/providers"
178
159
  cp template/.scripts/lib/ticket-provider.sh "$RD/.scripts/lib/"
179
- cp template/.scripts/providers/linear.sh "$RD/.scripts/providers/"
180
- printf 'repo: demo\nrole: pm\nticket_provider:\n name: linear\n team: DEL\n' \
160
+ cp template/.scripts/providers/plane.sh "$RD/.scripts/providers/"
161
+ printf 'repo: demo\nrole: pm\nticket_provider:\n name: plane\n workspace: 33god\n project: <project-uuid>\n' \
181
162
  > "$RD/role.yaml"
182
163
 
183
164
  # 3. Run the read operations.
@@ -199,5 +180,4 @@ verification.
199
180
  ## Read next
200
181
 
201
182
  - [Development guide](development.md): the full edit, validate, and propagate
202
- workflow, plus the open roadmap, which includes live-verifying Plane and
203
- Trello.
183
+ workflow, plus the open roadmap, which includes live-verifying Trello.
@@ -15,10 +15,10 @@
15
15
  #
16
16
  # Environment overrides (skip the prompts):
17
17
  # HAT_REPO=<name> project/repo name (default: basename of CWD)
18
- # HAT_PROVIDER=linear|plane|trello (default: plane)
18
+ # HAT_PROVIDER=plane|trello (default: plane)
19
19
  # HAT_ROLES="pm" roles to install (default: pm)
20
20
  # HAT_DRY_RUN=1 print actions, change nothing
21
- # Provider creds: LINEAR_API_KEY | PLANE_API_KEY+PLANE_BASE | TRELLO_KEY+TRELLO_TOKEN
21
+ # Provider creds: PLANE_API_KEY+PLANE_BASE | TRELLO_KEY+TRELLO_TOKEN
22
22
  set -eu
23
23
 
24
24
  say() { printf '\033[36m%s\033[0m\n' "$*"; }
@@ -100,7 +100,7 @@ TOML
100
100
  fi
101
101
 
102
102
  # --- 4. Provider credentials + board binding ---------------------------------
103
- ask HAT_PROVIDER "Ticket provider (linear|plane|trello)" "plane"
103
+ ask HAT_PROVIDER "Ticket provider (plane|trello)" "plane"
104
104
  PROVIDER="$HAT_PROVIDER"
105
105
  ask HAT_REPO "Project/repo name" "$(basename "$PROJECT_DIR" | tr '[:upper:]' '[:lower:]')"
106
106
  REPO="$HAT_REPO"
@@ -109,7 +109,7 @@ PM_ENV="$HOME/.hermes/${REPO}-pm.env"
109
109
  # These get written into the pm role.yaml binding after render.
110
110
  # Pre-seed from optional env knobs so the install can run non-interactively.
111
111
  TP_WORKSPACE="${HAT_PLANE_WORKSPACE:-}"; TP_PROJECT="${HAT_PLANE_PROJECT:-}"
112
- TP_TEAM="${HAT_LINEAR_TEAM:-}"; TP_BOARD="${HAT_TRELLO_BOARD:-}"
112
+ TP_BOARD="${HAT_TRELLO_BOARD:-}"
113
113
  case "$PROVIDER" in
114
114
  plane)
115
115
  ask PLANE_BASE "Plane base URL" "https://app.plane.so"
@@ -136,12 +136,6 @@ PY
136
136
  CRED_LINES="PLANE_API_KEY=$PLANE_API_KEY
137
137
  PLANE_BASE=$PLANE_BASE"
138
138
  ;;
139
- linear)
140
- : "${LINEAR_API_KEY:?Set LINEAR_API_KEY in your environment, then re-run}"
141
- ask TP_TEAM "Linear team key (for example DEL)" ""
142
- [ -n "$TP_TEAM" ] || die "team key is required"
143
- CRED_LINES="LINEAR_API_KEY=$LINEAR_API_KEY"
144
- ;;
145
139
  trello)
146
140
  : "${TRELLO_KEY:?Set TRELLO_KEY in your environment, then re-run}"
147
141
  : "${TRELLO_TOKEN:?Set TRELLO_TOKEN in your environment, then re-run}"
@@ -170,7 +164,7 @@ for ROLE in $ROLES; do
170
164
  DEST="$PROJECT_DIR/agents/hermes/$ROLE"
171
165
  # Scrub provider creds from copier's environment so 42-ticket-provider skips
172
166
  # board CREATION; we bind to the existing board in step 6 instead.
173
- run "env -u PLANE_API_KEY -u PLANE_33GOD_API_KEY -u LINEAR_API_KEY \
167
+ run "env -u PLANE_API_KEY -u PLANE_33GOD_API_KEY \
174
168
  -u TRELLO_KEY -u TRELLO_TOKEN \
175
169
  copier copy '$TEMPLATE_SRC' '$DEST' --trust --defaults --overwrite \
176
170
  --data target_repo='$REPO' --data role='$ROLE' --data ticket_provider='$PROVIDER'"
@@ -180,7 +174,7 @@ done
180
174
  PM_ROLE="$PROJECT_DIR/agents/hermes/pm/role.yaml"
181
175
  if [ -f "$PM_ROLE" ] && [ "${HAT_DRY_RUN:-0}" != "1" ]; then
182
176
  say "6. binding pm to your $PROVIDER board"
183
- TP_WORKSPACE="$TP_WORKSPACE" TP_PROJECT="$TP_PROJECT" TP_TEAM="$TP_TEAM" \
177
+ TP_WORKSPACE="$TP_WORKSPACE" TP_PROJECT="$TP_PROJECT" \
184
178
  TP_BOARD="$TP_BOARD" PROVIDER="$PROVIDER" python3 - "$PM_ROLE" <<'PY'
185
179
  import os, re, sys, pathlib
186
180
  p = pathlib.Path(sys.argv[1]); t = p.read_text()
@@ -190,7 +184,6 @@ def setleaf(text, key, val):
190
184
  return new if n else text
191
185
  t = setleaf(t, "workspace", os.environ.get("TP_WORKSPACE",""))
192
186
  t = setleaf(t, "project", os.environ.get("TP_PROJECT",""))
193
- t = setleaf(t, "team", os.environ.get("TP_TEAM",""))
194
187
  t = setleaf(t, "board", os.environ.get("TP_BOARD",""))
195
188
  p.write_text(t)
196
189
  print(" bound:", {k:v for k,v in os.environ.items() if k.startswith("TP_") and v})
@@ -46,13 +46,13 @@ PY
46
46
  }
47
47
 
48
48
  # pj_write — merge board binding (optional) + this agent into .project.json.
49
- # args: set_provider(0|1) provider board_id board_url workspace identifier team
49
+ # args: set_provider(0|1) provider board_id board_url workspace identifier
50
50
  pj_write() {
51
51
  REPO="$REPO" REPO_ROOT="$REPO_ROOT" AGENT_ID="$AGENT_ID" ROLE="$ROLE" \
52
52
  ROLE_DIR_REL="$ROLE_DIR_REL" PROJECT_DESC="${PROJECT_DESC:-}" \
53
53
  python3 - "$PROJECT_JSON" "$@" <<'PY'
54
54
  import sys, os, json, pathlib
55
- (path, set_provider, provider, board_id, board_url, workspace, identifier, team) = sys.argv[1:9]
55
+ (path, set_provider, provider, board_id, board_url, workspace, identifier) = sys.argv[1:8]
56
56
  p = pathlib.Path(path)
57
57
  try:
58
58
  d = json.loads(p.read_text())
@@ -72,7 +72,6 @@ if set_provider == "1":
72
72
  if identifier: tp["identifier"] = identifier
73
73
  if board_id: tp["board_id"] = board_id
74
74
  if board_url: tp["board_url"] = board_url
75
- if team: tp["team"] = team
76
75
  ag = d.setdefault("agents", {})
77
76
  ag[os.environ["AGENT_ID"]] = {"role": os.environ["ROLE"], "role_dir": os.environ["ROLE_DIR_REL"]}
78
77
  p.write_text(json.dumps(d, indent=2) + "\n")
@@ -82,8 +81,8 @@ PY
82
81
 
83
82
  # Mirror the binding into role.yaml so legacy consumers keep working.
84
83
  mirror_to_role_yaml() {
85
- # mirror_to_role_yaml <provider> <board_id> <board_url> <workspace> <identifier> <team>
86
- local provider="$1" bid="$2" burl="$3" ws="$4" ident="$5" team="$6"
84
+ # mirror_to_role_yaml <provider> <board_id> <board_url> <workspace> <identifier>
85
+ local provider="$1" bid="$2" burl="$3" ws="$4" ident="$5"
87
86
  yaml_set ticket_provider.name "$provider" 2>/dev/null || true
88
87
  [ -n "$bid" ] && yaml_set ticket_provider.board_id "$bid" 2>/dev/null || true
89
88
  [ -n "$burl" ] && yaml_set ticket_provider.board_url "$burl" 2>/dev/null || true
@@ -98,8 +97,8 @@ mirror_to_role_yaml() {
98
97
  trello)
99
98
  [ -n "$bid" ] && yaml_set ticket_provider.board "$bid" 2>/dev/null || true
100
99
  ;;
101
- linear)
102
- [ -n "$team" ] && yaml_set ticket_provider.team "$team" 2>/dev/null || true
100
+ *)
101
+ die "unsupported ticket provider: $provider (expected plane|trello)"
103
102
  ;;
104
103
  esac
105
104
  }
@@ -111,7 +110,6 @@ SOT_BOARD_ID="$(pj ticket_provider.board_id)"
111
110
  SOT_URL="$(pj ticket_provider.board_url)"
112
111
  SOT_WS="$(pj ticket_provider.workspace)"
113
112
  SOT_IDENT="$(pj ticket_provider.identifier)"
114
- SOT_TEAM="$(pj ticket_provider.team)"
115
113
 
116
114
  # role.yaml provider comes from copier --data (the operator's pjangler choice).
117
115
  ROLE_PROVIDER="$(yaml_get ticket_provider.name)"
@@ -122,9 +120,10 @@ if [ -n "$SOT_BOARD_ID" ]; then
122
120
  if [ -n "$ROLE_PROVIDER" ] && [ "$ROLE_PROVIDER" != "$PROVIDER" ]; then
123
121
  warn "[42] requested provider '$ROLE_PROVIDER' but repo board is '$PROVIDER' (.project.json wins); binding to existing board"
124
122
  fi
123
+ case "$PROVIDER" in plane|trello) ;; *) die "unsupported ticket provider in .project.json: $PROVIDER (expected plane|trello)" ;; esac
125
124
  log "[42] binding $AGENT_ID to existing repo board (provider=$PROVIDER, id=$SOT_BOARD_ID)"
126
- mirror_to_role_yaml "$PROVIDER" "$SOT_BOARD_ID" "$SOT_URL" "$SOT_WS" "$SOT_IDENT" "$SOT_TEAM"
127
- pj_write 0 "$PROVIDER" "" "" "" "" "" # register agent only; board already recorded
125
+ mirror_to_role_yaml "$PROVIDER" "$SOT_BOARD_ID" "$SOT_URL" "$SOT_WS" "$SOT_IDENT"
126
+ pj_write 0 "$PROVIDER" "" "" "" "" # register agent only; board already recorded
128
127
  mark_done 42-ticket-provider
129
128
  exit 0
130
129
  fi
@@ -143,45 +142,23 @@ NAME="$(printf '%s' "$REPO" | tr '_-' ' ' | python3 -c 'import sys; print(" ".j
143
142
  DESC="Ticket board for $REPO"
144
143
 
145
144
  case "$PROVIDER" in
146
- linear)
147
- if [[ -z "${LINEAR_API_KEY:-}" ]]; then
148
- warn "[42] LINEAR_API_KEY not set; set role.yaml/.project.json ticket_provider.team and re-run ./.scripts/42-ticket-provider.sh"
149
- pj_write 1 linear "" "" "" "$IDENT" "$SOT_TEAM"
150
- mark_done 42-ticket-provider; exit 0
151
- fi
152
- OUT="$(tp resolve 2>/dev/null || true)"
153
- BID="$(printf '%s' "$OUT" | python3 -c 'import sys,json
154
- try: print(json.load(sys.stdin).get("board_id",""))
155
- except Exception: print("")')"
156
- BURL="$(printf '%s' "$OUT" | python3 -c 'import sys,json
157
- try: print(json.load(sys.stdin).get("board_url",""))
158
- except Exception: print("")')"
159
- if [ -n "$BID" ]; then
160
- mirror_to_role_yaml linear "$BID" "$BURL" "" "$IDENT" "$SOT_TEAM"
161
- pj_write 1 linear "$BID" "$BURL" "" "$IDENT" "$SOT_TEAM"
162
- else
163
- warn "[42] linear resolve returned no board; set ticket_provider.team and re-run"
164
- pj_write 1 linear "" "" "" "$IDENT" "$SOT_TEAM"
165
- fi
166
- ;;
167
-
168
145
  plane|trello)
169
146
  KEYVAR=PLANE_API_KEY; [ "$PROVIDER" = trello ] && KEYVAR=TRELLO_KEY
170
147
  if [[ -z "${!KEYVAR:-}" ]]; then
171
148
  warn "[42] $KEYVAR not set; skipping board creation. Set creds and re-run ./.scripts/42-ticket-provider.sh"
172
- pj_write 1 "$PROVIDER" "" "" "${SOT_WS:-$PLANE_WORKSPACE}" "$IDENT" ""
149
+ pj_write 1 "$PROVIDER" "" "" "${SOT_WS:-${PLANE_WORKSPACE:-}}" "$IDENT"
173
150
  mark_done 42-ticket-provider; exit 0
174
151
  fi
175
152
  OUT="$(tp create_board "$NAME" "$IDENT" "$DESC")" || die "create_board failed for $PROVIDER"
176
153
  BID="$(printf '%s' "$OUT" | python3 -c 'import sys,json; print(json.load(sys.stdin).get("board_id",""))')"
177
154
  BURL="$(printf '%s' "$OUT" | python3 -c 'import sys,json; print(json.load(sys.stdin).get("board_url",""))')"
178
- WS="${SOT_WS:-$PLANE_WORKSPACE}"
155
+ WS="${SOT_WS:-${PLANE_WORKSPACE:-}}"
179
156
  [ "$PROVIDER" = trello ] && WS=""
180
- mirror_to_role_yaml "$PROVIDER" "$BID" "$BURL" "$WS" "$IDENT" ""
181
- pj_write 1 "$PROVIDER" "$BID" "$BURL" "$WS" "$IDENT" ""
157
+ mirror_to_role_yaml "$PROVIDER" "$BID" "$BURL" "$WS" "$IDENT"
158
+ pj_write 1 "$PROVIDER" "$BID" "$BURL" "$WS" "$IDENT"
182
159
  ;;
183
160
 
184
- *) die "unknown ticket provider: $PROVIDER (expected linear|plane|trello)" ;;
161
+ *) die "unknown ticket provider: $PROVIDER (expected plane|trello)" ;;
185
162
  esac
186
163
 
187
164
  mark_done 42-ticket-provider
@@ -33,6 +33,7 @@ Environment=HERMES_HOME=$RUNTIME
33
33
  Environment=HERMES_OAUTH_FILE=$HERMES_OAUTH_FILE
34
34
  Environment=CODEX_HOME=$CODEX_HOME
35
35
  Environment=HERMES_KANBAN_DISPATCH_IN_GATEWAY=0
36
+ Environment=HERMES_KANBAN_SLASH_ENABLED=0
36
37
  EnvironmentFile=-$RUNTIME/.env
37
38
  ExecStart=$HERMES_BIN gateway run --replace
38
39
  Restart=on-failure
@@ -1,6 +1,6 @@
1
1
  # shellcheck shell=bash
2
2
  # Ticket-provider adapter dispatcher — the single seam between the heartbeat
3
- # sentinel engine and a concrete ticket system (Linear | Plane | Trello).
3
+ # sentinel engine and a concrete ticket system (Plane | Trello).
4
4
  #
5
5
  # The engine NEVER calls a provider directly. It calls `tp <op> [args...]`,
6
6
  # which dispatches to providers/<provider>.sh. Swapping providers is a one-line
@@ -64,7 +64,7 @@ PY
64
64
  )"
65
65
  [ -n "$name" ] && { printf '%s\n' "$name"; return 0; }
66
66
  fi
67
- printf 'linear\n'
67
+ printf 'plane\n'
68
68
  }
69
69
 
70
70
  # Directory holding provider implementations (sibling of this lib).
@@ -81,6 +81,10 @@ tp() {
81
81
 
82
82
  local name impl
83
83
  name="$(tp_provider_name)"
84
+ case "$name" in
85
+ plane|trello) ;;
86
+ *) echo "tp: unsupported ticket provider '$name' (expected plane|trello)" >&2; return 2 ;;
87
+ esac
84
88
  impl="$(tp_providers_dir)/${name}.sh"
85
89
 
86
90
  if [ ! -f "$impl" ]; then
@@ -13,7 +13,7 @@ actively tries to break the work, surface unmet acceptance criteria, hidden
13
13
  regressions, and drift. On a clean adversarial verdict the loop treats the
14
14
  ticket as done and moves on — through the ticket-provider adapter
15
15
  (`tp transition <id> <state>`) — and emits a BloodBank decision event carrying
16
- the full report. This works identically on Linear, Plane, or Trello.
16
+ the full report. This works identically on Plane or Trello.
17
17
 
18
18
  The operator's verification is **deferred** to end-of-product QA over the review
19
19
  lane, backed by a queryable decision trail. A downstream regression rollback is
@@ -144,7 +144,7 @@ Write `<ISSUE>.review.md`; the script validates it:
144
144
  ```markdown
145
145
  # Autonomous Review Report: <ISSUE>
146
146
  ## Issue
147
- - Linear/Plane/Trello issue: <ISSUE>
147
+ - Provider issue: <ISSUE>
148
148
  - Review lane reason:
149
149
  ## Reviewer
150
150
  - Reviewer agent: <independent-agent-id>
@@ -19,7 +19,7 @@ approve merges.
19
19
  All board access goes through the adapter (`tp`, from
20
20
  `.scripts/lib/ticket-provider.sh`) and reasons in normalized states:
21
21
  `backlog | unstarted | started | in_review | completed`. Never call the provider
22
- directly — the engine is identical across Linear, Plane, and Trello.
22
+ directly — the engine is identical across Plane and Trello.
23
23
 
24
24
  ## Work-state feed
25
25
 
@@ -6,13 +6,11 @@ A cheap systemd heartbeat already decided this full pass is needed.
6
6
  Working repo: the git root containing this role at `agents/hermes/{{ role }}/`.
7
7
  Ticket provider: **{{ ticket_provider }}** (reached only through the adapter — see below).
8
8
 
9
- {% if ticket_provider == "plane" -%}
10
- **Plane is the authoritative repo ticket board/SOT for this PM.** Hermes local
11
- Kanban must NOT be an active durable task lifecycle surface. Local Kanban may
12
- only run as an explicitly configured ephemeral child execution queue and must
13
- never close/move authoritative repo tickets.
9
+ The configured ticket provider is the authoritative repo ticket board/SOT for
10
+ this PM. Hermes local Kanban must NOT be an active durable task lifecycle
11
+ surface. Local Kanban may only run as an explicitly configured ephemeral child
12
+ execution queue and must never close/move authoritative repo tickets.
14
13
 
15
- {% endif -%}
16
14
  You are the **{{ target_repo }} PM**, running your continuous board-reconciliation
17
15
  pass. Act autonomously, but stay inside the project contracts. Read
18
16
  `agents/hermes/{{ role }}/SOUL.md` and the engine docs under
@@ -34,7 +32,7 @@ tp transition <id> <normalized-state> # backlog|unstarted|started|in_review|com
34
32
  ```
35
33
 
36
34
  Reason in **normalized states**, not provider terms. This pass works identically
37
- on Linear, Plane, or Trello.
35
+ on Plane or Trello.
38
36
 
39
37
  ## Pass
40
38
 
@@ -55,17 +55,18 @@ read it before publishing a type you haven't published before.
55
55
  {% if role == "pm" -%}
56
56
  You are the **project manager**. You triage incoming requests from Telegram /
57
57
  Bloodbank command lanes, decompose them into discrete tasks on the
58
- **Plane board only**, and route work to other agents in the fleet (e.g. the dev role
58
+ configured ticket board, and route work to other agents in the fleet (e.g. the dev role
59
59
  on `bloodbank.cmd.v1.agent.{{ target_repo }}-dev.task.assign`). You do not
60
60
  write application code. You do not approve merges.
61
61
 
62
- **Plane is the authoritative repo ticket board/SOT for this PM.** Hermes local
63
- Kanban must NOT be an active durable task lifecycle surface. The kanban toolset
64
- is removed from the PM's cli surface. Local Kanban may only run as an explicitly-configured
65
- ephemeral child execution queue and must never close/move authoritative repo tickets.
62
+ The configured ticket provider (`{{ ticket_provider }}`) is the authoritative
63
+ repo ticket board/SOT for this PM. Hermes local Kanban must NOT be an active
64
+ durable task lifecycle surface. The kanban toolset is removed from the PM's cli
65
+ surface. Local Kanban may only run as an explicitly configured ephemeral child
66
+ execution queue and must never close/move authoritative repo tickets.
66
67
 
67
68
  Default execution workflow for implementation delivery: use
68
- `subagent-driven-development` in Plane-ticket-orchestrated implementation mode
69
+ `subagent-driven-development` in provider-ticket-orchestrated implementation mode
69
70
  (WIP=1, spec review gate, quality review gate).
70
71
 
71
72
  Decision events you commonly emit:
@@ -111,7 +112,7 @@ declared` event so the fleet knows what to route to you.
111
112
  - **Hostnames**: Use `*.delo.sh` for external/cross-machine access (resolved
112
113
  via Cloudflare Tunnel), `localhost` for same-host, Docker network service
113
114
  names for container-to-container, Tailscale for private machine-to-machine.
114
- - **Plane**: Always include a Plane ticket reference in commit messages.
115
+ - **Ticketing**: Always include the configured provider's ticket reference in commit messages.
115
116
 
116
117
  ## Memory hygiene
117
118