[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71F253YWHZVZV9W66A615MZ":3,"skill-same:01M71F253YWHZVZV9W66A615MZ":79},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":43,"linkOnly":44,"markdownContent":45,"markdownBody":46,"frontMatter":47,"refName":58,"commitSha":59,"skillDirectory":60,"forksCount":61,"repositoryHtmlUrl":62,"repositoryHomepageUrl":6,"ownerHtmlUrl":63,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":64,"install":65,"resources":78},"01M71F253YWHZVZV9W66A615MZ","trello-mcp-workflow",null,"Automated Trello board integration for ai-specs projects. Provides session bootstrapping, card linking, state synchronization, and progress reporting through Trello MCP tool calls.","parada1104\u002Fai-specs-cli","parada1104","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F57575053?v=4","01M71EZZV71KAFZKJ47FQ99ZVS","01M71EZZW7JJBY2VAWA5HRD944",0,"MIT","https:\u002F\u002Fgithub.com\u002Fparada1104\u002Fai-specs-cli\u002Fblob\u002Fmain\u002Fcatalog\u002Frecipes\u002Ftrello-mcp-workflow\u002Fskills\u002Ftrello-mcp-workflow\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42],"trello","trello mcp workflow","MCP","workflow","live","new","request","unknown","linking","card","progress","feature","active","feature request","work","synchronization","projects","work on","reporting","change","2026-11-10 10:12:30",false,"---\nname: trello-mcp-workflow\ndescription: >\n  Automated Trello board integration for ai-specs\n  projects. Provides session bootstrapping, card linking, state\n  synchronization, and progress reporting through Trello MCP tool calls.\nlicense: MIT\nmetadata:\n  author: ai-specs\n  version: \"1.0\"\n  scope: runtime\n  auto_invoke:\n    - \"New structured change or feature request\"\n    - \"Active change is missing a linked Trello card\"\n    - \"Resuming work on a change with a stale or unknown card\"\n    - \"Reconciling the ledger card against live Trello state\"\n---\n\n# Trello MCP Workflow\n\n## Prerequisites\n\n- Trello MCP server configured and reachable in the runtime environment.\n- On session start, read `board_id` from `[recipes.trello-mcp-workflow.config]` in `ai-specs\u002Fai-specs.toml`. The board ID is a 24-hex-character string (not the 8-character shortLink from the Trello URL).\n- Board ID available either in recipe config (`board_id`) or bootstrap marker file (`\u003CAI_SPECS_HOME>\u002Fcache\u002Fprojects\u002F\u003Chash>-\u003Cname>\u002F.recipe\u002Ftrello-mcp-workflow\u002Fbootstrap-ready`; legacy project-local fallback: `.recipe\u002Ftrello-mcp-workflow\u002Fbootstrap-ready`).\n- Agent has access to Trello MCP tools: `trello_get_active_board_info`, `trello_get_lists`, `trello_get_cards_by_list_id`, `trello_add_card_to_list`, `trello_add_comment`, `trello_move_card`, `trello_update_card_details`, `trello_get_card`.\n- Forbidden tools: `trello_get_my_cards` and `trello_list_boards` MUST NOT be invoked. See Board Isolation section below.\n\n## Configuration\n\n| Field | Required | Default | Description |\n|---|---|---|---|\n| `board_id` | Yes | — | Trello board ID for the project. Example: `69ec097f13e2d38ecd89a557`. |\n| `default_list` | No | `In Progress` | List name where new cards are created when no phase-specific list applies. |\n| `epic_list` | No | `Epic` | List name where epic-type cards are placed. |\n| `review_list` | No | `Review` | List a card must reach when the `review` lifecycle event reconciles. |\n| `done_list` | No | `Done` | List a card must reach when the `merge` lifecycle event reconciles (the default merge target). |\n| `published_list` | No | — | Optional list that means the merge was also published\u002Freleased. When set, the `merge` event reconciles against it instead of `done_list`. No default is invented: leave it unset when the board has no such list. |\n| `gate_mode` | No | `warn` | **Deprecated compatibility only**: legacy `off` \u002F `warn` \u002F `always` for the Tracker card gate. The tracker is advisory and never blocks source changes; prefer `ledger_mode`. |\n| `ledger_mode` | No | `warn` | **Canonical** Tracker mode: `always` \u002F `ask` \u002F `warn`. Tracker checkpoints never block — a `block` \u002F `ask` \u002F `needs-item` verdict is reported and the host continues. `always` is the strictest verdict and still governs the Plan Build `work-start` checkpoint, which may block separately. |\n| `reconcile` | No | — | Declarative remote-reconciliation mapping (`scope_field`, `max_age_seconds`, `expectations`). The recipe declares the lifecycle mapping by default (delivery\u002Freview\u002Fmerge); a project `[recipes.trello-mcp-workflow.config.reconcile]` block, when present, overrides it. Re-run `ai-specs sync` after recipe changes to propagate defaults. |\n\nConfiguration is read from `[recipes.trello-mcp-workflow.config]` in `ai-specs\u002Fai-specs.toml`.\n\n---\n\n## Board Isolation\n\nThe recipe enforces board isolation to prevent the agent from accessing Trello data outside the configured `board_id`. All capabilities MUST comply with these rules.\n\n### Forbidden Tools\n\nThe following MCP tools MUST NOT be invoked by any capability:\n\n| Tool | Restriction | Rationale |\n|---|---|---|\n| `trello_get_my_cards` | **Forbidden** — never invoke | Returns cards across all boards; leaks scope |\n| `trello_list_boards` | **Forbidden** — never invoke | Enumerates all accessible boards; leaks scope |\n\nIf a step references one of these tools, the call MUST be skipped and a warning emitted to stderr. Violations MUST be logged to `.recipe\u002Ftrello-mcp-workflow\u002Fwarnings.log`.\n\n### Restricted Tools\n\n| Tool | Restriction | Rationale |\n|---|---|---|\n| `trello_set_active_board` | **Restricted** — bootstrap only (guard + setup) | Required once per session; later calls bypass guard |\n\n`trello_set_active_board` MAY only be called during `trello-session-bootstrap`: inside the board guard precondition (guard step 3 — retry on mismatch) and during explicit session setup (bootstrap step 3). Any capability other than bootstrap that attempts this call MUST skip it and emit a warning.\n\n### Board Guard\n\nThe board guard is a precondition check that verifies the Trello MCP server's active board matches the configured `board_id`. Every capability MUST run the board guard as its first step (step 0):\n\n1. Read `board_id` from `[recipes.trello-mcp-workflow.config]` in `ai-specs\u002Fai-specs.toml`.\n2. Call `trello_get_active_board_info()`.\n3. If the returned board ID does not match the configured `board_id`, call `trello_set_active_board(board_id)` and retry the check.\n4. If the mismatch persists after one retry, log a warning to `.recipe\u002Ftrello-mcp-workflow\u002Fwarnings.log` with timestamp and capability name, then skip Trello operations for this session.\n\n### Card idBoard Validation\n\nBefore calling `trello_get_card` or `trello_add_comment` on any card, the agent MUST:\n\n1. Call `trello_get_card(cardId, fields=\"idBoard\")`.\n2. If the returned `idBoard` does not match the configured `board_id`, log a warning to `.recipe\u002Ftrello-mcp-workflow\u002Fwarnings.log` with card ID and board ID, then abort the operation.\n\n---\n\n## Capability: trello-session-bootstrap\n\nDetect the active card and recommend the next task for the session.\n\n### Trigger\n\nSession start when the bootstrap marker exists at `\u003CAI_SPECS_HOME>\u002Fcache\u002Fprojects\u002F\u003Chash>-\u003Cname>\u002F.recipe\u002Ftrello-mcp-workflow\u002Fbootstrap-ready` (legacy project-local fallback `.recipe\u002Ftrello-mcp-workflow\u002Fbootstrap-ready`), or when the agent explicitly invokes bootstrap.\n\n### Steps\n\n1. **Board guard**: Run the board guard precondition (see Board Isolation section above). If the guard fails and Trello operations are skipped, terminate bootstrap gracefully.\n2. Enforce forbidden-tools compliance: ensure `trello_get_my_cards` and `trello_list_boards` are never invoked. If a step references them, skip the call and emit a warning.\n3. Read `board_id` from `[recipes.trello-mcp-workflow.config]` in `ai-specs\u002Fai-specs.toml` (or from the marker file context). Call `trello_set_active_board(board_id)` to set the board as active for subsequent operations.\n4. Query the board using `trello_get_active_board_info()` or `trello_get_lists(boardId: \u003Cboard_id>)` to retrieve structural context.\n5. Detect the active card:\n   - Fetch cards in **In Progress** and **In Review** lists using `trello_get_cards_by_list_id(listId: \u003Cid>, boardId: \u003Cboard_id>)`.\n   - Match on labels, keywords in card names, or change references found in card comments\u002Fdescriptions.\n   - If multiple candidates exist, prefer the card with the most recent activity.\n6. Present the recommended next task to the agent, including:\n   - Card name, current list, current phase label.\n   - Suggested action (continue phase, start next phase, review, etc.).\n7. Feed structured primitives (card ID, list ID, label IDs) into the session's consensus check so subsequent capabilities can reference them without re-querying.\n8. **Graceful degradation**: If any Trello MCP call fails, emit a warning to stderr and continue the session without Trello context. Log the failure to `.recipe\u002Ftrello-mcp-workflow\u002Fwarnings.log`.\n\n---\n\n\n## Card link section (`## Tracker`)\n\nThe sole card-link contract for active changes is a `## Tracker` section inside\nthe change's `proposal.md` (fallback: `tasks.md` for tasks-only changes). No\nseparate artifact file and no folder-schema `trello_card_id` field.\n\n```markdown\n## Tracker\n\n- **card_id**: `\u003C24-hex>`\n- **shortLink**: `\u003C8-char>`          # optional\n- **url**: https:\u002F\u002Ftrello.com\u002Fc\u002F...\n- **list**: \u003Clist name>              # optional\n- **pr**: https:\u002F\u002Fgithub.com\u002F...     # optional\n```\n\n**Validity** (shared by doctor and the tracker-card gate): the section exists\nand yields a non-empty `card_id`. `url` is expected; its absence is an INFO\nnudge, not a block. Vocabulary that still says `trello_card_id` means the\n`card_id` recorded in this section.\n\nAfter creating or linking a card, agents MUST write this section before\napply\u002Fproduction work. The only documented exemption is\n`openspec\u002Fchanges\u002F\u003Cslug>\u002Ftracker.none` (conceptual name `tracker:none`) with a\none-line reason — log it; this is rare.\n\n**The ledger records the item; the artifact only presents it.** The `## Tracker`\nsection is **artifact sugar only** — presentation, never authority: it **never\nopens or binds** a ledger row. An item is opened, linked, closed, and exempted only\nby explicit writes, and grading never writes:\n\n```bash\nworktree-gate --ledger --checkpoint apply-start --write '{\"kind\":\"open\"}'\nworktree-gate --ledger --checkpoint apply-start \\\n  --write '{\"kind\":\"link\",\"item_id\":\"\u003C24-hex>\",\"url\":\"https:\u002F\u002Ftrello.com\u002Fc\u002F...\",\"native_type\":\"card\",\"state\":\"in-progress\"}'\n```\n\nA failed write exits `2`, persists nothing, and prints no verdict JSON; a retried\n`open` reports `already-open` instead of creating a second item.\n\n**`bind` is the generic binding command** for SDD, ODD, and no-flow work alike.\nAfter the provider item exists — a Trello card just created or already linked — the\nagent performs the exact local bind write. One `--write` opens-if-absent and links\nin the same locked transaction, so the branch binding is seeded from that valid\nexternal tracker item with no `openspec\u002F`\u002FSDD\u002FODD artifact and no provider call:\n\n```bash\nworktree-gate --ledger --checkpoint apply-start --ledger-mode \u003Cmode> \\\n  --project-root \u003Croot> \\\n  --write '{\"kind\":\"bind\",\"item_id\":\"\u003C24-hex>\",\"url\":\"https:\u002F\u002Ftrello.com\u002Fc\u002F...\",\"native_type\":\"card\",\"state\":\"in-progress\",\"provider\":{\"list\":\"\u003Clist name>\"}}'\n```\n\nThe bind payload is `kind=bind` with the card's `item_id`, `url`, `native_type`\n(`card`), a provider-neutral `state`, and the opaque `provider` snapshot (here the\nobserved list name). The Go core stores that provider object without reading it, so\nno Trello vocabulary enters the ledger core.\n\n**Ask path (`ledger_mode = ask`).** At the start of the cycle the gate can return a\n`needs-item` verdict (decision `ask`): no provider-backed item is bound yet. The\nagent's options are to **create or link** the provider card and then bind it locally\nwith the write above, or to record the human's explicit decline once. The decline is\n**lifecycle-scoped**: it covers the change lifecycle and is **not repeated** at\nevery checkpoint. Record it explicitly — never inferred, never automatic:\n\n```bash\nworktree-gate --ledger --checkpoint apply-start --ledger-mode ask --project-root \u003Croot> \\\n  --decide '{\"checkpoint\":\"apply-start\",\"kind\":\"opt-out\",\"choice\":\"continue\"}'\n```\n\nAn explicit decline is not a `tracker.none` exemption and creates no item.\n\nThe `ask` prompt is advisory: run without a terminal it reports the pending\n`needs-item` state, records no opt-out, and proceeds without blocking. A recorded\ndecline is lifecycle-scoped and is not repeated at later checkpoints.\n\nA `bind` without `change` is a deliberate branch-level binding: it links the single\nopen row for the same common dir and branch regardless of its stored slug, refuses\n(fail closed, nothing persisted) when several open rows exist, and otherwise opens a\nbranch-only item, so external binding needs no artifact. A `bind` that carries an\nexplicit `change` keeps the slug-keyed identity. A retried `bind` reports `unchanged`\ninstead of duplicating, and a closed row is never reopened (D17). State stays in the\nexisting Go ledger at `\u003Cgit-common-dir>\u002Fai-specs\u002Fledger\u002Fstate.json`, and nothing is\nwritten into the repository tree.\n\nFor `tracker.none`,\nthe human\u002Fagent records the exemption with an explicit write so every checkpoint\nhonors it and it never registers as a conflict:\n\n```bash\nworktree-gate --ledger --checkpoint apply-start \\\n  --write '{\"kind\":\"exempt\",\"reason\":\"\u003Cone line>\"}'\n```\n\nThe file itself is presentation\u002Fevidence only — no host auto-records it (R1); hosts\ntreat it as blank `code` evidence and never create, modify, or delete the file.\nRemoving the file does not revoke a recorded exemption — reopen evidence with\n`worktree-gate --ledger --checkpoint \u003Cname> --decide '{\"kind\":\"adjudicate\",\"choice\":\"\u003Cside>\"}'`.\nHosts grade with `local`\u002F`code`\u002F`git` evidence built from local facts; the `remote`\nside is unwired in this slice.\n\n### Tracker lifecycle checkpoints (`pre-merge`, `archive-close`)\n\nThe ledger's lifecycle is **Plan Build-independent**: this recipe never needs an\n`openspec\u002F` tree to grade a tracker checkpoint. Run the tracker gate's direct\nhost mode — this is the generic lifecycle command, and a future Jira\u002FLinear\nrecipe reuses it unchanged:\n\n```bash\nGATE=ai-specs\u002Frecipes\u002Ftrello-mcp-workflow\u002Fhooks\u002Ftracker-card-gate.sh\nbash \"$GATE\" --root \"$PWD\" --checkpoint pre-merge \u003Cslug>\nbash \"$GATE\" --root \"$PWD\" --checkpoint archive-close \u003Cslug>\n```\n\n`--root` is required and is the resolved project root, never the process cwd. The\nslug is optional: a tracker-only project has no change tree, and the binding\nwitness supplies the identity. `--stage pre-merge|pre-archive` remains a\ncompatibility alias for `--checkpoint pre-merge|archive-close`.\n\n**`archive-close` is tracker item closure, not an OpenSpec archive.** It asks the\none Go predicate whether the bound tracker item can be closed. It never moves\n`openspec\u002Fchanges\u002F\u003Cslug>\u002F`, never reads an OpenSpec archive to infer or select\nclosure, and never writes. The host is acquisition only: it resolves the mode,\nbuilds local evidence through `ledger_bridge.py`, calls\n`worktree-gate --ledger --checkpoint \u003Cname>`, and reports the verdict. The host\nis advisory: `block` \u002F `ask` \u002F `needs-item` are reported on stderr and it exits\n`0`, so a Tracker checkpoint never blocks a merge, a close, or source work. No\nprovider write, no network, no second grader.\n\nThe host and the ledger belong to the generic Tracker domain, not to Trello. A\nprovider recipe contributes only its `[config.reconcile]` native-state mapping;\nit never enables, configures, or implements the ledger, and it never grades.\n\n### Remote reconciliation (explicit, off the hot path)\n\nThe grade above compares local facts. Reconciling against what Trello *actually*\nreports is a separate, explicit comparison: the agent acquires the remote data\nthrough the Trello MCP tools and the Go gate compares it against the bound card and\nthe recipe-declared expectations. The comparison is never automatic, never a\nprovider write, and never resolves a decision — it rides along as a sidecar and the\ngraded exit code is unchanged.\n\n**1. Observe through MCP (board isolation still applies).** After the board guard,\nread the linked card with `trello_get_card(cardId, fields=\"idBoard,idList,name\")`,\nvalidate `idBoard` against the configured `board_id`, and resolve the card's list\nname with `trello_get_lists(boardId: \u003Cboard_id>)`. Report only what you actually\nread — never the state you expected to find.\n\n**2. Write the observation payload outside the repository** (for example to\n`$(mktemp)`), so no workspace file changes and the worktree gate stays untouched:\n\n```json\n{\n  \"provider_id\": \"trello-mcp-workflow\",\n  \"scope\": \"\u003Cboard_id>\",\n  \"item_id\": \"\u003C24-hex card id>\",\n  \"observed_at\": \"\u003CRFC3339 UTC stamp of this read>\",\n  \"event\": \"\u003Cthe event you observed, e.g. delivery>\",\n  \"properties\": { \"list\": \"\u003Clist name you read>\" }\n}\n```\n\nThe payload is a closed shape: `provider_id`, `scope`, `item_id`, `observed_at`,\n`event`, `properties` are the only accepted keys, unknown keys are rejected, and\nvalues must be the types shown. `observed_at` is the moment of the read, not a\nremembered or inferred time. The payload is read under a fixed size budget\n(1048576 bytes): a larger file is reported as `observation-invalid`, never parsed.\n\n**3. Compare with the gate**, naming the event you are asking about\n(`--reconcile-event`). At a delivery, review, or merge lifecycle transition the\nagent\u002Fprovider adapter reads the card through MCP, produces this closed observation\npayload, and calls\n`worktree-gate --ledger --reconcile \u003Cobservation> --reconcile-event \u003Cevent>`; the Go\nledger compares and **only `agree` is provider-backed compliance**. The comparison\nkeeps the Go ledger **provider-neutral**: it reads the neutral\npayload, performs **no provider write**, and touches no provider state — provider\ncalls live only in the adapter (the agent's MCP reads), never in the core. Use the\nstamped\u002Fverified gate binary path (`$WORKTREE_GATE_BIN`\nor the CLI cache path the hooks use). The recipe declares the supported lifecycle\nmapping by default — `delivery` → `default_list` (In Progress), `review` →\n`review_list` (Review), `merge` → `done_list` (Done), or → `published_list` when the\nproject configured that optional list — so a synced project reconciles without\nper-project configuration; the project's `[config.reconcile]` block, when present,\noverrides it:\n\n```bash\nworktree-gate --ledger --checkpoint apply-start --project-root \"$PWD\" \\\n  --reconcile \"$OBSERVATION\" --reconcile-event delivery\n```\n\nReconciliation is read-only: the gate refuses `--reconcile` combined with `--write`\nor `--decide` with exit 2 before it touches the store, it never writes the store —\na conflicting grade's conflict snapshot is suppressed instead of recorded and the\nsuppression is reported on stderr — and it never resolves a decision or changes the\ngraded exit code.\n\n**4. Read the sidecar** (top-level `reconcile` key of the verdict JSON):\n\n| Outcome | Meaning | Next step |\n|---|---|---|\n| `agree` | Every declared property matches for the requested event, and the observation reported that event. | Conditional expectation met. Still not proof of delivery. |\n| `unconfigured` | The manifest, the recipe's `[config.reconcile]` mapping, or a config value it selects is missing, or the recipe is `enabled = false`. | Re-run `ai-specs sync` so recipe defaults propagate; read `detail`. A readable, explicitly disabled recipe grants no authority. |\n| `unmapped-event` | No expectation is declared for the requested event. | Pending \u002F unreconciled: declare the mapping or drop the request. |\n| `event-mismatch` | The observation reports a different (or no) event than the one requested. | Never treat the requested event as observed; re-read or re-request. |\n| `observation-invalid` | The payload is missing, malformed, oversized, or carries unknown keys. | Fix the acquisition; nothing was compared. |\n| `unbound-identity`, `identity-mismatch` | No bound card, or the observation belongs to another provider\u002Fscope\u002Fitem. | Fix the binding or the observation; wrong scope is never compared. |\n| `stale-observation`, `future-observed-at`, `invalid-observed-at`, `invalid-window`, `invalid-clock` | The observation is older than the declared window, dated in the future, unparsable, or the freshness window is undeclared. | Re-read; bind a positive `max_age_seconds` no larger than `9223372036`. There is no freshness default. |\n| `missing-property`, `property-mismatch` | A declared property was not reported or holds another value. | Report the discrepancy and present it as a pending explicit decision. |\n\nOnly `agree` is agreement. A selected event is never evidence that the event\nhappened, a local property match is not a merge\u002Frelease verification, and a\nnon-agreeing outcome is information to report — it does not block unrelated work and\nit creates no provider write.\n\n**Pending decisions (every non-agree outcome).** Agreement is a conditional match\nof the declared expectations for the requested event, not proof that the event was\ndelivered. Every non-agreeing outcome above is a *pending explicit decision*: the\nagent presents it and the human resolves it. Nothing is resolved by the agent, by a\nprovider write, or by treating silence as consent. Only the **disputed action** (for\nexample claiming the card is merged\u002Freleased, or recording local state as done) is\nsuspended; unrelated work in the session continues normally.\n\nFor one non-agree outcome, the agent presents, in one message:\n\n- The `outcome` and what it means (the table above).\n- The event asked for (`requested_event`) against the event actually observed\n  (`observed_event`); an unobserved event is never the requested one.\n- The bound identity this comparison was about: `provider_id`, `scope`, `item_id`.\n  An empty `item_id` means nothing was bound — never borrow another card's id.\n- `observed_at` and its age against the declared `max_age_seconds`; an age the\n  agent cannot compute is reported as unknown, not as fresh.\n- The `findings` list verbatim when it carries entries (`property`, `expected`,\n  `observed`, `status`), or the bounded `detail` string for the wiring outcomes\n  (`unconfigured`, `unmapped-event`, `observation-invalid`) that carry none.\n\nThen it asks **exactly one** `ask_user` question offering exactly these\nresolutions:\n\n| Resolution | What it does |\n|---|---|\n| **Fix remote state and re-observe** | Correct the card in Trello, then re-read and re-run the `--reconcile` comparison. The agent never edits the card on its own initiative. |\n| **Record observed state as truth** | The human decides what the observed state means and the agent performs the explicit ledger write (`--write` \u002F `--decide`) that records it. Never inferred, never automatic. |\n| **Leave pending** | No resolution now: report the item as unreconciled and continue unrelated work. It is re-raised on the next explicit reconciliation, not silently dropped. |\n\nHard rules:\n\n- **No inferred consent.** An unanswered, dismissed, or defaulted prompt is not a\n  yes. `record observed state as truth` requires an explicit human selection; the\n  agent never selects it for the human, and it never re-asks with a leading option.\n- **No provider mutation before an explicit human choice.** Until the human\n  chooses, the agent performs no Trello create\u002Fupdate\u002Fmove\u002Fcomment\u002Flabel call and\n  no provider-adjacent write. Running the comparison is not consent.\n- **Unrelated work continues.** A pending decision suspends only the disputed\n  action; it never blocks the session, other tasks, or the graded exit code.\n- **Headless or unavailable UI leaves the decision pending.** When no interactive\n  prompt is available, the agent does not guess a resolution: it reports the\n  outcome as pending\u002Funreconciled with the same fields above and leaves it for a\n  session that can ask.\n- **Agreement is conditional expectation match, not delivery proof.** `agree` means\n  only that the declared properties matched for the requested event; it is not\n  evidence of a merge, a release, or a delivery.\n- **Closed items after a merge are locally corroborated.** D17 keeps a closed row\n  out of the primary slot, so a merge comparison has no bound card by default. It\n  binds one only when the observation's item id matches exactly one locally stored\n  closed row for the current identity: that corroborated row is compared read-only,\n  never reopened, and never selected for new work. An id with no local match, or\n  with more than one, stays `unbound-identity` and is presented as a pending\n  decision — never guessed and never trusted from the provider alone.\n\nReading the mapping is bounded acquisition: the manifest must be a plain file, and\nthe standard parser runs under a deadline with capped output. A missing parser, a\nhung parser, an oversized result, a non-TOML manifest, and an invalid mapping all\nreach the sidecar as `unconfigured` with a bounded `detail` — never as raw parser\noutput.\n\n**Declared mapping.** The recipe declares the lifecycle mapping and its\nconservative list defaults. During `ai-specs sync`, the mapping and the config\nvalues it references are stamped into `[recipes.trello-mcp-workflow.config]`\nwhen absent; explicit project values remain overrides and are never replaced.\nA project that has not been synced after this recipe version can temporarily\nreport `unconfigured`; re-run sync rather than authoring a reconcile block by\nhand:\n\n```toml\n[recipes.trello-mcp-workflow.config]\ndefault_list = \"In Progress\"\nreview_list = \"Review\"\ndone_list = \"Done\"\n# Optional; set it only when the board has a Published-style list. Omit it and the\n# merge event keeps reconciling against done_list.\n# published_list = \"Published\"\n\n[recipes.trello-mcp-workflow.config.reconcile]\nscope_field = \"board_id\"\nmax_age_seconds = 900\n\n[[recipes.trello-mcp-workflow.config.reconcile.expectations]]\nevent = \"delivery\"\nproperty = \"list\"\nconfig_field = \"default_list\"\n\n[[recipes.trello-mcp-workflow.config.reconcile.expectations]]\nevent = \"review\"\nproperty = \"list\"\nconfig_field = \"review_list\"\n\n[[recipes.trello-mcp-workflow.config.reconcile.expectations]]\nevent = \"merge\"\nproperty = \"list\"\nconfig_field = \"done_list\"\nconfig_field_when_set = \"published_list\"\n```\n\nEach expectation means \"when the caller asks about `event`, the property `property`\nmust show the value configured in `config_field`\". `config_field_when_set` is an\noptional conditional target: the merge expectation compares `published_list` when\nthe project configured that list, and `done_list` otherwise. The condition is\ndeclared by the recipe, so a project still configures list names only — it never\nhand-authors which property maps to which list, and no Published list is invented.\n`max_age_seconds` must be positive and at most `9223372036`; anything else is\n`unconfigured`, never a clamped default. When there is no open card, a merge\ncomparison binds a closed row only through the locally corroborated id described\nabove; the gate never guesses a closed row.\n\n---\n\n## Capability: trello-card-linking\n\nLink a structured change to a Trello card. Create a card from a template when no existing card matches.\n\n### Trigger\n\nNew structured change or feature request.\n\n### Steps\n\n0. **Board guard**: Run the board guard precondition (see Board Isolation section above). If the guard fails and Trello operations are skipped, terminate this capability gracefully.\n1. Detect whether a Trello card is already linked:\n   - Check the `## Tracker` section of the change's `proposal.md` (fallback `tasks.md`).\n   - Search recent comments on candidate cards for references to the change folder path.\n   - Before calling `trello_get_card`, run card idBoard validation (see Card idBoard Validation above).\n2. **If a card exists**: Post a structured linking comment using `trello_add_comment` with:\n   - Before calling `trello_add_comment`, run card idBoard validation.\n   - Change name.\n   - Change folder path (relative to project root).\n   - List of expected artifacts.\n3. **If no card exists**: Prompt the agent to create one from a bundled template:\n   - Select template type: `feature`, `bug`, `spike`, `epic`, or `handoff`.\n   - Create the card in `default_list` using `trello_add_card_to_list(..., boardId: \u003Cboard_id>)`.\n   - Post the initial linking comment (same structure as step 2) using `trello_add_comment` with card idBoard validation.\n4. **Record the link** in the `## Tracker` section of the change's `proposal.md` (or `tasks.md`) with at least `card_id` + `url`.\n5. **Only omit a card** by writing `openspec\u002Fchanges\u002F\u003Cslug>\u002Ftracker.none` with a one-line reason; log the exemption (stderr and\u002For `.recipe\u002Ftrello-mcp-workflow\u002Fwarnings.log`). This is rare — declining card creation without `tracker.none` is not a free pass.\n\n### Templates\n\nTemplates are located at `ai-specs\u002Frecipes\u002Ftrello-mcp-workflow\u002Foverrides\u002Ftemplates\u002F` and are installed by the recipe:\n\n| Template | File | Use Case |\n|---|---|---|\n| Feature | `card-feature.md` | New capabilities, commands, recipes, skills. |\n| Bug | `card-bug.md` | Regressions or fixes with reproduction steps. |\n| Spike | `card-spike.md` | Research with go\u002Fno-go conclusion. |\n| Epic | `card-epic.md` | Grouping cards; no direct code implementation. |\n| Handoff | `card-handoff.md` | Session continuity between agents. |\n\n---\n\n## Capability: trello-state-sync\n\nSynchronize project phase transitions with Trello card position and labels.\n\n### Trigger\n\nPhase transitions defined by the project's workflow (e.g., design → implementation → review → done).\n\n### Steps\n\n0. **Board guard**: Run the board guard precondition (see Board Isolation section above). If the guard fails and Trello operations are skipped, terminate this capability gracefully.\n1. Identify the linked card (from session context or change metadata). Run card idBoard validation before calling `trello_get_card`.\n2. Resolve the target list ID by name using board lists (query with `trello_get_lists(boardId: \u003Cboard_id>)`).\n3. Move the card to the target list using `trello_move_card(cardId, listId, boardId: \u003Cboard_id>)`.\n4. Update labels on the card using `trello_update_card_details(cardId, boardId: \u003Cboard_id>, ...)`.\n5. Post a phase-transition comment using `trello_add_comment`. Run card idBoard validation before calling `trello_add_comment`.\n\nPhase-to-list and phase-to-label mappings are project-specific and configured in the recipe config or project conventions.\n\n### Graceful Degradation\n\nIf the target list does not exist on the board, emit a warning, skip the move, and continue with the label update. Log the failure to `.recipe\u002Ftrello-mcp-workflow\u002Fwarnings.log`.\n\n---\n\n## Capability: trello-progress-comment\n\nPost a structured progress comment on the linked card after significant implementation milestones.\n\n### Trigger\n\nAfter significant implementation milestones or at project-defined review points.\n\n### Steps\n\n0. **Board guard**: Run the board guard precondition (see Board Isolation section above). If the guard fails and Trello operations are skipped, terminate this capability gracefully.\n1. Identify the linked card (from session context or change metadata). Run card idBoard validation before calling `trello_get_card`.\n2. Collect available progress data (changed files, test results, review notes) from the project workspace.\n3. Assemble a structured comment:\n   ```markdown\n   ## Progress: {phase}\n\n   **Status**: {description of current state}\n   **Files Changed**: {count} files — added: {list}, modified: {list}, removed: {list}\n   ```\n4. Post the comment using `trello_add_comment`. Run card idBoard validation before calling `trello_add_comment`.\n\n### Graceful Degradation\n\nIf progress data files are unavailable, post the comment with available data and mark missing sections as `unavailable`.\n\n---\n\n## Graceful Degradation (General)\n\n- All runtime Trello **availability** failures (MCP\u002Fnetwork\u002FAPI down) emit warnings to stderr and continue — never block.\n- Optionally log warnings to `.recipe\u002Ftrello-mcp-workflow\u002Fwarnings.log` with timestamp, capability, and error detail.\n- A **missing `## Tracker` link section** is **not** an availability failure. Do not claim 'Trello unavailable' to skip it; create\u002Flink the card and write the section (or write `tracker.none` with a logged reason). The tracker-card gate reports a warn\u002Fblock\u002Fask verdict when the artifact is missing, but it is advisory and never blocks source or PR\u002Farchive work.\n- If the Trello MCP server is unreachable, skip Trello MCP calls for the remainder of the session and log a single warning — but still do not invent an availability excuse for a missing link section once MCP is back.\n\n---\n\n## MCP Tools Reference\n\n| Tool | Used By | Purpose | Board Isolation |\n|---|---|---|---|\n| `trello_get_active_board_info` | session-bootstrap | Retrieve board structure and current state. | Board guard uses this to verify active board. |\n| `trello_get_lists` | session-bootstrap, state-sync | Resolve list names to IDs. | Must pass `boardId: \u003Cboard_id>`. |\n| `trello_get_cards_by_list_id` | session-bootstrap | Fetch cards in active lists to detect the current card. | Must pass `boardId: \u003Cboard_id>`. |\n| `trello_get_card` | card-linking, state-sync, progress-comment | Retrieve card details for matching and comment assembly. | Must validate `idBoard` before use. |\n| `trello_add_card_to_list` | card-linking | Create a new card from a template. | Must pass `boardId: \u003Cboard_id>`. |\n| `trello_add_comment` | card-linking, state-sync, progress-comment | Post structured comments on cards. | Must validate `idBoard` before use. |\n| `trello_move_card` | state-sync | Move a card to a new list on phase transition. | Must pass `boardId: \u003Cboard_id>`. |\n| `trello_update_card_details` | state-sync | Replace phase labels on a card. | Must pass `boardId: \u003Cboard_id>`. |\n\n---\n\n## Card Contract\n\nThe automation above (capabilities, board isolation, templates) defines *how* the\nagent drives Trello. This section defines *what* a good card looks like and how PM\nwork is structured. Board IDs and list names are never hardcoded here — read them\nfrom `[recipes.trello-mcp-workflow.config]` in `ai-specs\u002Fai-specs.toml`.\n\n### Separation of concerns\n\n- **Trello** tracks state, priority, dependencies, and PM\u002FCTO visibility.\n- **Canonical store** holds durable decisions and handoffs.\n- **Operational memory** holds searchable session continuity.\n- **SDD artifacts** hold specs\u002Fdesign\u002Ftasks when a card requires durable change.\n\nDo not mix these: Trello is state, not memory. A card links to its decision\u002Fspec\nrecords; it does not duplicate them.\n\n### Card types\n\n| Type | Use | Template |\n|---|---|---|\n| `epic` | Groups cards; no direct code. | `card-epic.md` |\n| `feature` | New capability, command, recipe, skill, or behavior. | `card-feature.md` |\n| `bug` | Regression or fix with reproduction + regression test. | `card-bug.md` |\n| `spike` | Research with a go\u002Fno-go conclusion. | `card-spike.md` |\n| `decision` | Tradeoff that must be recorded in the canonical store. | `card-decision.md` |\n| `handoff` | Session-to-session continuity when the active card is not enough. | `card-handoff.md` |\n\nTemplates install to `ai-specs\u002Frecipes\u002Ftrello-mcp-workflow\u002Foverrides\u002Ftemplates\u002F`.\n\n### Card base structure\n\nEvery work card carries: Context (why it exists), Objective (one sentence),\nScope (checklist of deliverables), Out of scope, Acceptance Criteria (verifiable),\nDependencies (blocking cards\u002Fchanges), and Notes (links, decisions).\n\n### Flow rules\n\n- One session works one explicit request, one card, or one change.\n- A card that implies implementation, durable design, or a complex technical\n  decision should map to an SDD cycle.\n- A card may block another; dependencies must be explicit in Trello.\n- A card should link or name its SDD change when one exists.\n- Do not move a blocked card into apply while its dependencies stay open.\n\n### SDD checklist for features\n\nAdd to the card when applicable:\n\n```markdown\n- [ ] Change created in a dedicated worktree\n- [ ] Proposal complete\n- [ ] Specs complete\n- [ ] Design complete\n- [ ] Tasks complete\n- [ ] Apply executed\n- [ ] Verify report generated\n- [ ] PR \u002F merge done if applicable\n- [ ] Change archived if applicable\n```\n\n### Card close ritual\n\nBefore moving a card to Review\u002FDone:\n\n- Verify the acceptance criteria.\n- Confirm the state of SDD artifacts if SDD was used.\n- Record the decision\u002Fhandoff in the canonical store if it changes project canon.\n- Save operational memory only if it helps future sessions.\n- Leave links to the PR, change, verify report, or handoff.\n","# Trello MCP Workflow\n\n## Prerequisites\n\n- Trello MCP server configured and reachable in the runtime environment.\n- On session start, read `board_id` from `[recipes.trello-mcp-workflow.config]` in `ai-specs\u002Fai-specs.toml`. The board ID is a 24-hex-character string (not the 8-character shortLink from the Trello URL).\n- Board ID available either in recipe config (`board_id`) or bootstrap marker file (`\u003CAI_SPECS_HOME>\u002Fcache\u002Fprojects\u002F\u003Chash>-\u003Cname>\u002F.recipe\u002Ftrello-mcp-workflow\u002Fbootstrap-ready`; legacy project-local fallback: `.recipe\u002Ftrello-mcp-workflow\u002Fbootstrap-ready`).\n- Agent has access to Trello MCP tools: `trello_get_active_board_info`, `trello_get_lists`, `trello_get_cards_by_list_id`, `trello_add_card_to_list`, `trello_add_comment`, `trello_move_card`, `trello_update_card_details`, `trello_get_card`.\n- Forbidden tools: `trello_get_my_cards` and `trello_list_boards` MUST NOT be invoked. See Board Isolation section below.\n\n## Configuration\n\n| Field | Required | Default | Description |\n|---|---|---|---|\n| `board_id` | Yes | — | Trello board ID for the project. Example: `69ec097f13e2d38ecd89a557`. |\n| `default_list` | No | `In Progress` | List name where new cards are created when no phase-specific list applies. |\n| `epic_list` | No | `Epic` | List name where epic-type cards are placed. |\n| `review_list` | No | `Review` | List a card must reach when the `review` lifecycle event reconciles. |\n| `done_list` | No | `Done` | List a card must reach when the `merge` lifecycle event reconciles (the default merge target). |\n| `published_list` | No | — | Optional list that means the merge was also published\u002Freleased. When set, the `merge` event reconciles against it instead of `done_list`. No default is invented: leave it unset when the board has no such list. |\n| `gate_mode` | No | `warn` | **Deprecated compatibility only**: legacy `off` \u002F `warn` \u002F `always` for the Tracker card gate. The tracker is advisory and never blocks source changes; prefer `ledger_mode`. |\n| `ledger_mode` | No | `warn` | **Canonical** Tracker mode: `always` \u002F `ask` \u002F `warn`. Tracker checkpoints never block — a `block` \u002F `ask` \u002F `needs-item` verdict is reported and the host continues. `always` is the strictest verdict and still governs the Plan Build `work-start` checkpoint, which may block separately. |\n| `reconcile` | No | — | Declarative remote-reconciliation mapping (`scope_field`, `max_age_seconds`, `expectations`). The recipe declares the lifecycle mapping by default (delivery\u002Freview\u002Fmerge); a project `[recipes.trello-mcp-workflow.config.reconcile]` block, when present, overrides it. Re-run `ai-specs sync` after recipe changes to propagate defaults. |\n\nConfiguration is read from `[recipes.trello-mcp-workflow.config]` in `ai-specs\u002Fai-specs.toml`.\n\n---\n\n## Board Isolation\n\nThe recipe enforces board isolation to prevent the agent from accessing Trello data outside the configured `board_id`. All capabilities MUST comply with these rules.\n\n### Forbidden Tools\n\nThe following MCP tools MUST NOT be invoked by any capability:\n\n| Tool | Restriction | Rationale |\n|---|---|---|\n| `trello_get_my_cards` | **Forbidden** — never invoke | Returns cards across all boards; leaks scope |\n| `trello_list_boards` | **Forbidden** — never invoke | Enumerates all accessible boards; leaks scope |\n\nIf a step references one of these tools, the call MUST be skipped and a warning emitted to stderr. Violations MUST be logged to `.recipe\u002Ftrello-mcp-workflow\u002Fwarnings.log`.\n\n### Restricted Tools\n\n| Tool | Restriction | Rationale |\n|---|---|---|\n| `trello_set_active_board` | **Restricted** — bootstrap only (guard + setup) | Required once per session; later calls bypass guard |\n\n`trello_set_active_board` MAY only be called during `trello-session-bootstrap`: inside the board guard precondition (guard step 3 — retry on mismatch) and during explicit session setup (bootstrap step 3). Any capability other than bootstrap that attempts this call MUST skip it and emit a warning.\n\n### Board Guard\n\nThe board guard is a precondition check that verifies the Trello MCP server's active board matches the configured `board_id`. Every capability MUST run the board guard as its first step (step 0):\n\n1. Read `board_id` from `[recipes.trello-mcp-workflow.config]` in `ai-specs\u002Fai-specs.toml`.\n2. Call `trello_get_active_board_info()`.\n3. If the returned board ID does not match the configured `board_id`, call `trello_set_active_board(board_id)` and retry the check.\n4. If the mismatch persists after one retry, log a warning to `.recipe\u002Ftrello-mcp-workflow\u002Fwarnings.log` with timestamp and capability name, then skip Trello operations for this session.\n\n### Card idBoard Validation\n\nBefore calling `trello_get_card` or `trello_add_comment` on any card, the agent MUST:\n\n1. Call `trello_get_card(cardId, fields=\"idBoard\")`.\n2. If the returned `idBoard` does not match the configured `board_id`, log a warning to `.recipe\u002Ftrello-mcp-workflow\u002Fwarnings.log` with card ID and board ID, then abort the operation.\n\n---\n\n## Capability: trello-session-bootstrap\n\nDetect the active card and recommend the next task for the session.\n\n### Trigger\n\nSession start when the bootstrap marker exists at `\u003CAI_SPECS_HOME>\u002Fcache\u002Fprojects\u002F\u003Chash>-\u003Cname>\u002F.recipe\u002Ftrello-mcp-workflow\u002Fbootstrap-ready` (legacy project-local fallback `.recipe\u002Ftrello-mcp-workflow\u002Fbootstrap-ready`), or when the agent explicitly invokes bootstrap.\n\n### Steps\n\n1. **Board guard**: Run the board guard precondition (see Board Isolation section above). If the guard fails and Trello operations are skipped, terminate bootstrap gracefully.\n2. Enforce forbidden-tools compliance: ensure `trello_get_my_cards` and `trello_list_boards` are never invoked. If a step references them, skip the call and emit a warning.\n3. Read `board_id` from `[recipes.trello-mcp-workflow.config]` in `ai-specs\u002Fai-specs.toml` (or from the marker file context). Call `trello_set_active_board(board_id)` to set the board as active for subsequent operations.\n4. Query the board using `trello_get_active_board_info()` or `trello_get_lists(boardId: \u003Cboard_id>)` to retrieve structural context.\n5. Detect the active card:\n   - Fetch cards in **In Progress** and **In Review** lists using `trello_get_cards_by_list_id(listId: \u003Cid>, boardId: \u003Cboard_id>)`.\n   - Match on labels, keywords in card names, or change references found in card comments\u002Fdescriptions.\n   - If multiple candidates exist, prefer the card with the most recent activity.\n6. Present the recommended next task to the agent, including:\n   - Card name, current list, current phase label.\n   - Suggested action (continue phase, start next phase, review, etc.).\n7. Feed structured primitives (card ID, list ID, label IDs) into the session's consensus check so subsequent capabilities can reference them without re-querying.\n8. **Graceful degradation**: If any Trello MCP call fails, emit a warning to stderr and continue the session without Trello context. Log the failure to `.recipe\u002Ftrello-mcp-workflow\u002Fwarnings.log`.\n\n---\n\n\n## Card link section (`## Tracker`)\n\nThe sole card-link contract for active changes is a `## Tracker` section inside\nthe change's `proposal.md` (fallback: `tasks.md` for tasks-only changes). No\nseparate artifact file and no folder-schema `trello_card_id` field.\n\n```markdown\n## Tracker\n\n- **card_id**: `\u003C24-hex>`\n- **shortLink**: `\u003C8-char>`          # optional\n- **url**: https:\u002F\u002Ftrello.com\u002Fc\u002F...\n- **list**: \u003Clist name>              # optional\n- **pr**: https:\u002F\u002Fgithub.com\u002F...     # optional\n```\n\n**Validity** (shared by doctor and the tracker-card gate): the section exists\nand yields a non-empty `card_id`. `url` is expected; its absence is an INFO\nnudge, not a block. Vocabulary that still says `trello_card_id` means the\n`card_id` recorded in this section.\n\nAfter creating or linking a card, agents MUST write this section before\napply\u002Fproduction work. The only documented exemption is\n`openspec\u002Fchanges\u002F\u003Cslug>\u002Ftracker.none` (conceptual name `tracker:none`) with a\none-line reason — log it; this is rare.\n\n**The ledger records the item; the artifact only presents it.** The `## Tracker`\nsection is **artifact sugar only** — presentation, never authority: it **never\nopens or binds** a ledger row. An item is opened, linked, closed, and exempted only\nby explicit writes, and grading never writes:\n\n```bash\nworktree-gate --ledger --checkpoint apply-start --write '{\"kind\":\"open\"}'\nworktree-gate --ledger --checkpoint apply-start \\\n  --write '{\"kind\":\"link\",\"item_id\":\"\u003C24-hex>\",\"url\":\"https:\u002F\u002Ftrello.com\u002Fc\u002F...\",\"native_type\":\"card\",\"state\":\"in-progress\"}'\n```\n\nA failed write exits `2`, persists nothing, and prints no verdict JSON; a retried\n`open` reports `already-open` instead of creating a second item.\n\n**`bind` is the generic binding command** for SDD, ODD, and no-flow work alike.\nAfter the provider item exists — a Trello card just created or already linked — the\nagent performs the exact local bind write. One `--write` opens-if-absent and links\nin the same locked transaction, so the branch binding is seeded from that valid\nexternal tracker item with no `openspec\u002F`\u002FSDD\u002FODD artifact and no provider call:\n\n```bash\nworktree-gate --ledger --checkpoint apply-start --ledger-mode \u003Cmode> \\\n  --project-root \u003Croot> \\\n  --write '{\"kind\":\"bind\",\"item_id\":\"\u003C24-hex>\",\"url\":\"https:\u002F\u002Ftrello.com\u002Fc\u002F...\",\"native_type\":\"card\",\"state\":\"in-progress\",\"provider\":{\"list\":\"\u003Clist name>\"}}'\n```\n\nThe bind payload is `kind=bind` with the card's `item_id`, `url`, `native_type`\n(`card`), a provider-neutral `state`, and the opaque `provider` snapshot (here the\nobserved list name). The Go core stores that provider object without reading it, so\nno Trello vocabulary enters the ledger core.\n\n**Ask path (`ledger_mode = ask`).** At the start of the cycle the gate can return a\n`needs-item` verdict (decision `ask`): no provider-backed item is bound yet. The\nagent's options are to **create or link** the provider card and then bind it locally\nwith the write above, or to record the human's explicit decline once. The decline is\n**lifecycle-scoped**: it covers the change lifecycle and is **not repeated** at\nevery checkpoint. Record it explicitly — never inferred, never automatic:\n\n```bash\nworktree-gate --ledger --checkpoint apply-start --ledger-mode ask --project-root \u003Croot> \\\n  --decide '{\"checkpoint\":\"apply-start\",\"kind\":\"opt-out\",\"choice\":\"continue\"}'\n```\n\nAn explicit decline is not a `tracker.none` exemption and creates no item.\n\nThe `ask` prompt is advisory: run without a terminal it reports the pending\n`needs-item` state, records no opt-out, and proceeds without blocking. A recorded\ndecline is lifecycle-scoped and is not repeated at later checkpoints.\n\nA `bind` without `change` is a deliberate branch-level binding: it links the single\nopen row for the same common dir and branch regardless of its stored slug, refuses\n(fail closed, nothing persisted) when several open rows exist, and otherwise opens a\nbranch-only item, so external binding needs no artifact. A `bind` that carries an\nexplicit `change` keeps the slug-keyed identity. A retried `bind` reports `unchanged`\ninstead of duplicating, and a closed row is never reopened (D17). State stays in the\nexisting Go ledger at `\u003Cgit-common-dir>\u002Fai-specs\u002Fledger\u002Fstate.json`, and nothing is\nwritten into the repository tree.\n\nFor `tracker.none`,\nthe human\u002Fagent records the exemption with an explicit write so every checkpoint\nhonors it and it never registers as a conflict:\n\n```bash\nworktree-gate --ledger --checkpoint apply-start \\\n  --write '{\"kind\":\"exempt\",\"reason\":\"\u003Cone line>\"}'\n```\n\nThe file itself is presentation\u002Fevidence only — no host auto-records it (R1); hosts\ntreat it as blank `code` evidence and never create, modify, or delete the file.\nRemoving the file does not revoke a recorded exemption — reopen evidence with\n`worktree-gate --ledger --checkpoint \u003Cname> --decide '{\"kind\":\"adjudicate\",\"choice\":\"\u003Cside>\"}'`.\nHosts grade with `local`\u002F`code`\u002F`git` evidence built from local facts; the `remote`\nside is unwired in this slice.\n\n### Tracker lifecycle checkpoints (`pre-merge`, `archive-close`)\n\nThe ledger's lifecycle is **Plan Build-independent**: this recipe never needs an\n`openspec\u002F` tree to grade a tracker checkpoint. Run the tracker gate's direct\nhost mode — this is the generic lifecycle command, and a future Jira\u002FLinear\nrecipe reuses it unchanged:\n\n```bash\nGATE=ai-specs\u002Frecipes\u002Ftrello-mcp-workflow\u002Fhooks\u002Ftracker-card-gate.sh\nbash \"$GATE\" --root \"$PWD\" --checkpoint pre-merge \u003Cslug>\nbash \"$GATE\" --root \"$PWD\" --checkpoint archive-close \u003Cslug>\n```\n\n`--root` is required and is the resolved project root, never the process cwd. The\nslug is optional: a tracker-only project has no change tree, and the binding\nwitness supplies the identity. `--stage pre-merge|pre-archive` remains a\ncompatibility alias for `--checkpoint pre-merge|archive-close`.\n\n**`archive-close` is tracker item closure, not an OpenSpec archive.** It asks the\none Go predicate whether the bound tracker item can be closed. It never moves\n`openspec\u002Fchanges\u002F\u003Cslug>\u002F`, never reads an OpenSpec archive to infer or select\nclosure, and never writes. The host is acquisition only: it resolves the mode,\nbuilds local evidence through `ledger_bridge.py`, calls\n`worktree-gate --ledger --checkpoint \u003Cname>`, and reports the verdict. The host\nis advisory: `block` \u002F `ask` \u002F `needs-item` are reported on stderr and it exits\n`0`, so a Tracker checkpoint never blocks a merge, a close, or source work. No\nprovider write, no network, no second grader.\n\nThe host and the ledger belong to the generic Tracker domain, not to Trello. A\nprovider recipe contributes only its `[config.reconcile]` native-state mapping;\nit never enables, configures, or implements the ledger, and it never grades.\n\n### Remote reconciliation (explicit, off the hot path)\n\nThe grade above compares local facts. Reconciling against what Trello *actually*\nreports is a separate, explicit comparison: the agent acquires the remote data\nthrough the Trello MCP tools and the Go gate compares it against the bound card and\nthe recipe-declared expectations. The comparison is never automatic, never a\nprovider write, and never resolves a decision — it rides along as a sidecar and the\ngraded exit code is unchanged.\n\n**1. Observe through MCP (board isolation still applies).** After the board guard,\nread the linked card with `trello_get_card(cardId, fields=\"idBoard,idList,name\")`,\nvalidate `idBoard` against the configured `board_id`, and resolve the card's list\nname with `trello_get_lists(boardId: \u003Cboard_id>)`. Report only what you actually\nread — never the state you expected to find.\n\n**2. Write the observation payload outside the repository** (for example to\n`$(mktemp)`), so no workspace file changes and the worktree gate stays untouched:\n\n```json\n{\n  \"provider_id\": \"trello-mcp-workflow\",\n  \"scope\": \"\u003Cboard_id>\",\n  \"item_id\": \"\u003C24-hex card id>\",\n  \"observed_at\": \"\u003CRFC3339 UTC stamp of this read>\",\n  \"event\": \"\u003Cthe event you observed, e.g. delivery>\",\n  \"properties\": { \"list\": \"\u003Clist name you read>\" }\n}\n```\n\nThe payload is a closed shape: `provider_id`, `scope`, `item_id`, `observed_at`,\n`event`, `properties` are the only accepted keys, unknown keys are rejected, and\nvalues must be the types shown. `observed_at` is the moment of the read, not a\nremembered or inferred time. The payload is read under a fixed size budget\n(1048576 bytes): a larger file is reported as `observation-invalid`, never parsed.\n\n**3. Compare with the gate**, naming the event you are asking about\n(`--reconcile-event`). At a delivery, review, or merge lifecycle transition the\nagent\u002Fprovider adapter reads the card through MCP, produces this closed observation\npayload, and calls\n`worktree-gate --ledger --reconcile \u003Cobservation> --reconcile-event \u003Cevent>`; the Go\nledger compares and **only `agree` is provider-backed compliance**. The comparison\nkeeps the Go ledger **provider-neutral**: it reads the neutral\npayload, performs **no provider write**, and touches no provider state — provider\ncalls live only in the adapter (the agent's MCP reads), never in the core. Use the\nstamped\u002Fverified gate binary path (`$WORKTREE_GATE_BIN`\nor the CLI cache path the hooks use). The recipe declares the supported lifecycle\nmapping by default — `delivery` → `default_list` (In Progress), `review` →\n`review_list` (Review), `merge` → `done_list` (Done), or → `published_list` when the\nproject configured that optional list — so a synced project reconciles without\nper-project configuration; the project's `[config.reconcile]` block, when present,\noverrides it:\n\n```bash\nworktree-gate --ledger --checkpoint apply-start --project-root \"$PWD\" \\\n  --reconcile \"$OBSERVATION\" --reconcile-event delivery\n```\n\nReconciliation is read-only: the gate refuses `--reconcile` combined with `--write`\nor `--decide` with exit 2 before it touches the store, it never writes the store —\na conflicting grade's conflict snapshot is suppressed instead of recorded and the\nsuppression is reported on stderr — and it never resolves a decision or changes the\ngraded exit code.\n\n**4. Read the sidecar** (top-level `reconcile` key of the verdict JSON):\n\n| Outcome | Meaning | Next step |\n|---|---|---|\n| `agree` | Every declared property matches for the requested event, and the observation reported that event. | Conditional expectation met. Still not proof of delivery. |\n| `unconfigured` | The manifest, the recipe's `[config.reconcile]` mapping, or a config value it selects is missing, or the recipe is `enabled = false`. | Re-run `ai-specs sync` so recipe defaults propagate; read `detail`. A readable, explicitly disabled recipe grants no authority. |\n| `unmapped-event` | No expectation is declared for the requested event. | Pending \u002F unreconciled: declare the mapping or drop the request. |\n| `event-mismatch` | The observation reports a different (or no) event than the one requested. | Never treat the requested event as observed; re-read or re-request. |\n| `observation-invalid` | The payload is missing, malformed, oversized, or carries unknown keys. | Fix the acquisition; nothing was compared. |\n| `unbound-identity`, `identity-mismatch` | No bound card, or the observation belongs to another provider\u002Fscope\u002Fitem. | Fix the binding or the observation; wrong scope is never compared. |\n| `stale-observation`, `future-observed-at`, `invalid-observed-at`, `invalid-window`, `invalid-clock` | The observation is older than the declared window, dated in the future, unparsable, or the freshness window is undeclared. | Re-read; bind a positive `max_age_seconds` no larger than `9223372036`. There is no freshness default. |\n| `missing-property`, `property-mismatch` | A declared property was not reported or holds another value. | Report the discrepancy and present it as a pending explicit decision. |\n\nOnly `agree` is agreement. A selected event is never evidence that the event\nhappened, a local property match is not a merge\u002Frelease verification, and a\nnon-agreeing outcome is information to report — it does not block unrelated work and\nit creates no provider write.\n\n**Pending decisions (every non-agree outcome).** Agreement is a conditional match\nof the declared expectations for the requested event, not proof that the event was\ndelivered. Every non-agreeing outcome above is a *pending explicit decision*: the\nagent presents it and the human resolves it. Nothing is resolved by the agent, by a\nprovider write, or by treating silence as consent. Only the **disputed action** (for\nexample claiming the card is merged\u002Freleased, or recording local state as done) is\nsuspended; unrelated work in the session continues normally.\n\nFor one non-agree outcome, the agent presents, in one message:\n\n- The `outcome` and what it means (the table above).\n- The event asked for (`requested_event`) against the event actually observed\n  (`observed_event`); an unobserved event is never the requested one.\n- The bound identity this comparison was about: `provider_id`, `scope`, `item_id`.\n  An empty `item_id` means nothing was bound — never borrow another card's id.\n- `observed_at` and its age against the declared `max_age_seconds`; an age the\n  agent cannot compute is reported as unknown, not as fresh.\n- The `findings` list verbatim when it carries entries (`property`, `expected`,\n  `observed`, `status`), or the bounded `detail` string for the wiring outcomes\n  (`unconfigured`, `unmapped-event`, `observation-invalid`) that carry none.\n\nThen it asks **exactly one** `ask_user` question offering exactly these\nresolutions:\n\n| Resolution | What it does |\n|---|---|\n| **Fix remote state and re-observe** | Correct the card in Trello, then re-read and re-run the `--reconcile` comparison. The agent never edits the card on its own initiative. |\n| **Record observed state as truth** | The human decides what the observed state means and the agent performs the explicit ledger write (`--write` \u002F `--decide`) that records it. Never inferred, never automatic. |\n| **Leave pending** | No resolution now: report the item as unreconciled and continue unrelated work. It is re-raised on the next explicit reconciliation, not silently dropped. |\n\nHard rules:\n\n- **No inferred consent.** An unanswered, dismissed, or defaulted prompt is not a\n  yes. `record observed state as truth` requires an explicit human selection; the\n  agent never selects it for the human, and it never re-asks with a leading option.\n- **No provider mutation before an explicit human choice.** Until the human\n  chooses, the agent performs no Trello create\u002Fupdate\u002Fmove\u002Fcomment\u002Flabel call and\n  no provider-adjacent write. Running the comparison is not consent.\n- **Unrelated work continues.** A pending decision suspends only the disputed\n  action; it never blocks the session, other tasks, or the graded exit code.\n- **Headless or unavailable UI leaves the decision pending.** When no interactive\n  prompt is available, the agent does not guess a resolution: it reports the\n  outcome as pending\u002Funreconciled with the same fields above and leaves it for a\n  session that can ask.\n- **Agreement is conditional expectation match, not delivery proof.** `agree` means\n  only that the declared properties matched for the requested event; it is not\n  evidence of a merge, a release, or a delivery.\n- **Closed items after a merge are locally corroborated.** D17 keeps a closed row\n  out of the primary slot, so a merge comparison has no bound card by default. It\n  binds one only when the observation's item id matches exactly one locally stored\n  closed row for the current identity: that corroborated row is compared read-only,\n  never reopened, and never selected for new work. An id with no local match, or\n  with more than one, stays `unbound-identity` and is presented as a pending\n  decision — never guessed and never trusted from the provider alone.\n\nReading the mapping is bounded acquisition: the manifest must be a plain file, and\nthe standard parser runs under a deadline with capped output. A missing parser, a\nhung parser, an oversized result, a non-TOML manifest, and an invalid mapping all\nreach the sidecar as `unconfigured` with a bounded `detail` — never as raw parser\noutput.\n\n**Declared mapping.** The recipe declares the lifecycle mapping and its\nconservative list defaults. During `ai-specs sync`, the mapping and the config\nvalues it references are stamped into `[recipes.trello-mcp-workflow.config]`\nwhen absent; explicit project values remain overrides and are never replaced.\nA project that has not been synced after this recipe version can temporarily\nreport `unconfigured`; re-run sync rather than authoring a reconcile block by\nhand:\n\n```toml\n[recipes.trello-mcp-workflow.config]\ndefault_list = \"In Progress\"\nreview_list = \"Review\"\ndone_list = \"Done\"\n# Optional; set it only when the board has a Published-style list. Omit it and the\n# merge event keeps reconciling against done_list.\n# published_list = \"Published\"\n\n[recipes.trello-mcp-workflow.config.reconcile]\nscope_field = \"board_id\"\nmax_age_seconds = 900\n\n[[recipes.trello-mcp-workflow.config.reconcile.expectations]]\nevent = \"delivery\"\nproperty = \"list\"\nconfig_field = \"default_list\"\n\n[[recipes.trello-mcp-workflow.config.reconcile.expectations]]\nevent = \"review\"\nproperty = \"list\"\nconfig_field = \"review_list\"\n\n[[recipes.trello-mcp-workflow.config.reconcile.expectations]]\nevent = \"merge\"\nproperty = \"list\"\nconfig_field = \"done_list\"\nconfig_field_when_set = \"published_list\"\n```\n\nEach expectation means \"when the caller asks about `event`, the property `property`\nmust show the value configured in `config_field`\". `config_field_when_set` is an\noptional conditional target: the merge expectation compares `published_list` when\nthe project configured that list, and `done_list` otherwise. The condition is\ndeclared by the recipe, so a project still configures list names only — it never\nhand-authors which property maps to which list, and no Published list is invented.\n`max_age_seconds` must be positive and at most `9223372036`; anything else is\n`unconfigured`, never a clamped default. When there is no open card, a merge\ncomparison binds a closed row only through the locally corroborated id described\nabove; the gate never guesses a closed row.\n\n---\n\n## Capability: trello-card-linking\n\nLink a structured change to a Trello card. Create a card from a template when no existing card matches.\n\n### Trigger\n\nNew structured change or feature request.\n\n### Steps\n\n0. **Board guard**: Run the board guard precondition (see Board Isolation section above). If the guard fails and Trello operations are skipped, terminate this capability gracefully.\n1. Detect whether a Trello card is already linked:\n   - Check the `## Tracker` section of the change's `proposal.md` (fallback `tasks.md`).\n   - Search recent comments on candidate cards for references to the change folder path.\n   - Before calling `trello_get_card`, run card idBoard validation (see Card idBoard Validation above).\n2. **If a card exists**: Post a structured linking comment using `trello_add_comment` with:\n   - Before calling `trello_add_comment`, run card idBoard validation.\n   - Change name.\n   - Change folder path (relative to project root).\n   - List of expected artifacts.\n3. **If no card exists**: Prompt the agent to create one from a bundled template:\n   - Select template type: `feature`, `bug`, `spike`, `epic`, or `handoff`.\n   - Create the card in `default_list` using `trello_add_card_to_list(..., boardId: \u003Cboard_id>)`.\n   - Post the initial linking comment (same structure as step 2) using `trello_add_comment` with card idBoard validation.\n4. **Record the link** in the `## Tracker` section of the change's `proposal.md` (or `tasks.md`) with at least `card_id` + `url`.\n5. **Only omit a card** by writing `openspec\u002Fchanges\u002F\u003Cslug>\u002Ftracker.none` with a one-line reason; log the exemption (stderr and\u002For `.recipe\u002Ftrello-mcp-workflow\u002Fwarnings.log`). This is rare — declining card creation without `tracker.none` is not a free pass.\n\n### Templates\n\nTemplates are located at `ai-specs\u002Frecipes\u002Ftrello-mcp-workflow\u002Foverrides\u002Ftemplates\u002F` and are installed by the recipe:\n\n| Template | File | Use Case |\n|---|---|---|\n| Feature | `card-feature.md` | New capabilities, commands, recipes, skills. |\n| Bug | `card-bug.md` | Regressions or fixes with reproduction steps. |\n| Spike | `card-spike.md` | Research with go\u002Fno-go conclusion. |\n| Epic | `card-epic.md` | Grouping cards; no direct code implementation. |\n| Handoff | `card-handoff.md` | Session continuity between agents. |\n\n---\n\n## Capability: trello-state-sync\n\nSynchronize project phase transitions with Trello card position and labels.\n\n### Trigger\n\nPhase transitions defined by the project's workflow (e.g., design → implementation → review → done).\n\n### Steps\n\n0. **Board guard**: Run the board guard precondition (see Board Isolation section above). If the guard fails and Trello operations are skipped, terminate this capability gracefully.\n1. Identify the linked card (from session context or change metadata). Run card idBoard validation before calling `trello_get_card`.\n2. Resolve the target list ID by name using board lists (query with `trello_get_lists(boardId: \u003Cboard_id>)`).\n3. Move the card to the target list using `trello_move_card(cardId, listId, boardId: \u003Cboard_id>)`.\n4. Update labels on the card using `trello_update_card_details(cardId, boardId: \u003Cboard_id>, ...)`.\n5. Post a phase-transition comment using `trello_add_comment`. Run card idBoard validation before calling `trello_add_comment`.\n\nPhase-to-list and phase-to-label mappings are project-specific and configured in the recipe config or project conventions.\n\n### Graceful Degradation\n\nIf the target list does not exist on the board, emit a warning, skip the move, and continue with the label update. Log the failure to `.recipe\u002Ftrello-mcp-workflow\u002Fwarnings.log`.\n\n---\n\n## Capability: trello-progress-comment\n\nPost a structured progress comment on the linked card after significant implementation milestones.\n\n### Trigger\n\nAfter significant implementation milestones or at project-defined review points.\n\n### Steps\n\n0. **Board guard**: Run the board guard precondition (see Board Isolation section above). If the guard fails and Trello operations are skipped, terminate this capability gracefully.\n1. Identify the linked card (from session context or change metadata). Run card idBoard validation before calling `trello_get_card`.\n2. Collect available progress data (changed files, test results, review notes) from the project workspace.\n3. Assemble a structured comment:\n   ```markdown\n   ## Progress: {phase}\n\n   **Status**: {description of current state}\n   **Files Changed**: {count} files — added: {list}, modified: {list}, removed: {list}\n   ```\n4. Post the comment using `trello_add_comment`. Run card idBoard validation before calling `trello_add_comment`.\n\n### Graceful Degradation\n\nIf progress data files are unavailable, post the comment with available data and mark missing sections as `unavailable`.\n\n---\n\n## Graceful Degradation (General)\n\n- All runtime Trello **availability** failures (MCP\u002Fnetwork\u002FAPI down) emit warnings to stderr and continue — never block.\n- Optionally log warnings to `.recipe\u002Ftrello-mcp-workflow\u002Fwarnings.log` with timestamp, capability, and error detail.\n- A **missing `## Tracker` link section** is **not** an availability failure. Do not claim 'Trello unavailable' to skip it; create\u002Flink the card and write the section (or write `tracker.none` with a logged reason). The tracker-card gate reports a warn\u002Fblock\u002Fask verdict when the artifact is missing, but it is advisory and never blocks source or PR\u002Farchive work.\n- If the Trello MCP server is unreachable, skip Trello MCP calls for the remainder of the session and log a single warning — but still do not invent an availability excuse for a missing link section once MCP is back.\n\n---\n\n## MCP Tools Reference\n\n| Tool | Used By | Purpose | Board Isolation |\n|---|---|---|---|\n| `trello_get_active_board_info` | session-bootstrap | Retrieve board structure and current state. | Board guard uses this to verify active board. |\n| `trello_get_lists` | session-bootstrap, state-sync | Resolve list names to IDs. | Must pass `boardId: \u003Cboard_id>`. |\n| `trello_get_cards_by_list_id` | session-bootstrap | Fetch cards in active lists to detect the current card. | Must pass `boardId: \u003Cboard_id>`. |\n| `trello_get_card` | card-linking, state-sync, progress-comment | Retrieve card details for matching and comment assembly. | Must validate `idBoard` before use. |\n| `trello_add_card_to_list` | card-linking | Create a new card from a template. | Must pass `boardId: \u003Cboard_id>`. |\n| `trello_add_comment` | card-linking, state-sync, progress-comment | Post structured comments on cards. | Must validate `idBoard` before use. |\n| `trello_move_card` | state-sync | Move a card to a new list on phase transition. | Must pass `boardId: \u003Cboard_id>`. |\n| `trello_update_card_details` | state-sync | Replace phase labels on a card. | Must pass `boardId: \u003Cboard_id>`. |\n\n---\n\n## Card Contract\n\nThe automation above (capabilities, board isolation, templates) defines *how* the\nagent drives Trello. This section defines *what* a good card looks like and how PM\nwork is structured. Board IDs and list names are never hardcoded here — read them\nfrom `[recipes.trello-mcp-workflow.config]` in `ai-specs\u002Fai-specs.toml`.\n\n### Separation of concerns\n\n- **Trello** tracks state, priority, dependencies, and PM\u002FCTO visibility.\n- **Canonical store** holds durable decisions and handoffs.\n- **Operational memory** holds searchable session continuity.\n- **SDD artifacts** hold specs\u002Fdesign\u002Ftasks when a card requires durable change.\n\nDo not mix these: Trello is state, not memory. A card links to its decision\u002Fspec\nrecords; it does not duplicate them.\n\n### Card types\n\n| Type | Use | Template |\n|---|---|---|\n| `epic` | Groups cards; no direct code. | `card-epic.md` |\n| `feature` | New capability, command, recipe, skill, or behavior. | `card-feature.md` |\n| `bug` | Regression or fix with reproduction + regression test. | `card-bug.md` |\n| `spike` | Research with a go\u002Fno-go conclusion. | `card-spike.md` |\n| `decision` | Tradeoff that must be recorded in the canonical store. | `card-decision.md` |\n| `handoff` | Session-to-session continuity when the active card is not enough. | `card-handoff.md` |\n\nTemplates install to `ai-specs\u002Frecipes\u002Ftrello-mcp-workflow\u002Foverrides\u002Ftemplates\u002F`.\n\n### Card base structure\n\nEvery work card carries: Context (why it exists), Objective (one sentence),\nScope (checklist of deliverables), Out of scope, Acceptance Criteria (verifiable),\nDependencies (blocking cards\u002Fchanges), and Notes (links, decisions).\n\n### Flow rules\n\n- One session works one explicit request, one card, or one change.\n- A card that implies implementation, durable design, or a complex technical\n  decision should map to an SDD cycle.\n- A card may block another; dependencies must be explicit in Trello.\n- A card should link or name its SDD change when one exists.\n- Do not move a blocked card into apply while its dependencies stay open.\n\n### SDD checklist for features\n\nAdd to the card when applicable:\n\n```markdown\n- [ ] Change created in a dedicated worktree\n- [ ] Proposal complete\n- [ ] Specs complete\n- [ ] Design complete\n- [ ] Tasks complete\n- [ ] Apply executed\n- [ ] Verify report generated\n- [ ] PR \u002F merge done if applicable\n- [ ] Change archived if applicable\n```\n\n### Card close ritual\n\nBefore moving a card to Review\u002FDone:\n\n- Verify the acceptance criteria.\n- Confirm the state of SDD artifacts if SDD was used.\n- Record the decision\u002Fhandoff in the canonical store if it changes project canon.\n- Save operational memory only if it helps future sessions.\n- Leave links to the PR, change, verify report, or handoff.\n",{"name":5,"license":14,"metadata":48,"description":57},{"scope":49,"author":50,"version":51,"auto_invoke":52},"runtime","ai-specs","1.0",[53,54,55,56],"New structured change or feature request","Active change is missing a linked Trello card","Resuming work on a change with a stale or unknown card","Reconciling the ledger card against live Trello state","Automated Trello board integration for ai-specs projects. Provides session bootstrapping, card linking, state synchronization, and progress reporting through Trello MCP tool calls.\n","main","c092fc1f51280350a4434827e2f6d6d99e3431ca","catalog\u002Frecipes\u002Ftrello-mcp-workflow\u002Fskills\u002Ftrello-mcp-workflow",2,"https:\u002F\u002Fgithub.com\u002Fparada1104\u002Fai-specs-cli","https:\u002F\u002Fgithub.com\u002Fparada1104","2026-11-14 03:51:03",{"source":8,"skillName":5,"commands":66,"prompt":76,"zipAvailable":77},[67,70,73],{"tool":68,"command":69},"npx","npx skills add parada1104\u002Fai-specs-cli --skill trello-mcp-workflow",{"tool":71,"command":72},"bunx","bunx skills add parada1104\u002Fai-specs-cli --skill trello-mcp-workflow",{"tool":74,"command":75},"pnpm","pnpm dlx skills add parada1104\u002Fai-specs-cli --skill trello-mcp-workflow","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fparada1104\u002Fai-specs-cli\u002Fblob\u002Fmain\u002Fcatalog\u002Frecipes\u002Ftrello-mcp-workflow\u002Fskills\u002Ftrello-mcp-workflow\u002FSKILL.md",true,[],[80,98,112,121,130,143],{"skillNo":81,"name":82,"nameZh":6,"description":83,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":84,"categories":85,"keywords":90,"publishedAt":43},"01M71F2TF9TS9DNCJ68M7C3B5S","test-skill","Test skill for fixture purposes.","https:\u002F\u002Fgithub.com\u002Fparada1104\u002Fai-specs-cli\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Frecipes\u002Ftest-fixture\u002Fskills\u002Ftest-skill\u002FSKILL.md",[86,89],{"categoryNo":87,"categoryName":88,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[91,92,93,94,95,96,97],"Test Skill","test","for","root","fixtures","fixture","testing",{"skillNo":99,"name":100,"nameZh":6,"description":101,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":102,"categories":103,"keywords":107,"publishedAt":43},"01M71F2RTH94ZB7XEAW4P6ZG0D","obsidian-markdown","Fixture skill for obsidian-markdown.","https:\u002F\u002Fgithub.com\u002Fparada1104\u002Fai-specs-cli\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fkepano-obsidian-skills\u002Fskills\u002Fobsidian-markdown\u002FSKILL.md",[104],{"categoryNo":105,"categoryName":106,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000002","文档处理",[108,109,110,93,96,111],"markdown","obsidian markdown","obsidian","fixture skill",{"skillNo":113,"name":114,"nameZh":6,"description":115,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":116,"categories":117,"keywords":118,"publishedAt":43},"01M71F2R20CPTJXD9F7DP4JPP6","obsidian-cli","Fixture skill for obsidian-cli.","https:\u002F\u002Fgithub.com\u002Fparada1104\u002Fai-specs-cli\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fkepano-obsidian-skills\u002Fskills\u002Fobsidian-cli\u002FSKILL.md",[],[119,110,120,93,96,111],"obsidian cli","cli",{"skillNo":122,"name":123,"nameZh":6,"description":124,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":125,"categories":126,"keywords":127,"publishedAt":43},"01M71F2PCH4NWVTT1J57SHJX33","obsidian-bases","Fixture skill for obsidian-bases.","https:\u002F\u002Fgithub.com\u002Fparada1104\u002Fai-specs-cli\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fkepano-obsidian-skills\u002Fskills\u002Fobsidian-bases\u002FSKILL.md",[],[128,129,110,93,96,111],"bases","obsidian bases",{"skillNo":131,"name":132,"nameZh":6,"description":133,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":134,"categories":135,"keywords":139,"publishedAt":43},"01M71F2MSS6EVFEYVYAA1KBYCC","json-canvas","Fixture skill for json-canvas.","https:\u002F\u002Fgithub.com\u002Fparada1104\u002Fai-specs-cli\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fkepano-obsidian-skills\u002Fskills\u002Fjson-canvas\u002FSKILL.md",[136],{"categoryNo":137,"categoryName":138,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000015","视觉设计",[140,141,142,111,96,93],"json","json canvas","canvas",{"skillNo":144,"name":145,"nameZh":6,"description":146,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":147,"categories":148,"keywords":149,"publishedAt":43},"01M71F2KY5QVNEN1Q3REFB0MQZ","defuddle","Fixture skill for defuddle.","https:\u002F\u002Fgithub.com\u002Fparada1104\u002Fai-specs-cli\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fkepano-obsidian-skills\u002Fskills\u002Fdefuddle\u002FSKILL.md",[],[145,111,96,93]]