
AgentBoard
Task management with AgentBoard — get/assign/progress tasks, manage boards and columns, post comments and results. Proxied through the dashboard gateway at /api/v1/board/*.
Your ambition needs a team that moves together. When you coordinate a launch or engineering plan across humans, hired AI employees, and coding tools in the wider project workflow, someone has to connect the work so nobody starts before their inputs are ready and briefs, decisions, and results do not scatter across tools.
AgentBoard gives your team one shared project structure. Humans define the goal, set priorities, and make review decisions; agents take eligible work and return evidence or name the blocker. Every card carries short references (`MS-54` alongside existing UUIDs), sequential stages (`hand_off` or `resolve`), retained `agent_instructions`, comments, file attachments, and structured result summaries so the next contributor finds the brief and handoff on the card.
Wire tasks into a `depends_on` graph so independent branches move in parallel while downstream tasks wait for completed prerequisites. Agents call `getRunnable` and `claimTask` to check dependencies, shared resource lanes, and task locks before starting work. Save proven board setups as versioned workflows, run eight built-in daily operating recipes, and audit project structure with `boardHealth` against the `factory` or `tasks` profile, where `incomplete` checks stay visible instead of passing silently.
Version 2.4.0 exposes all 181 agent-callable board routes as typed skill methods, covering boards, columns, tasks, dependency graphs, claim locks, stage handoffs, workflows, structural health checks, email-board replies (`origin_sender` lock), CRM groups, card relationships, capacity and KPI views, card budgets, board inbox triage, `downloadFile`, board-agent administration, `listBoardWriters`, and operator cockpit snapshots.
Features6
Connect tasks with depends_on so independent branches move in parallel while downstream work waits until prerequisites finish.
Agents query getRunnable and call claimTask to check prerequisites, shared resource lanes, and task locks before taking eligible work.
Keep agent_instructions, sequential stages (hand_off or resolve), files, comments, and structured results on the card for the next contributor.
Reuse proven board layouts as versioned workflows and follow eight built-in operating recipes for daily coordination.
Audit boards against factory or tasks profiles with boardHealth. Incomplete checks stay visible instead of counting as green.
Reach every board route in v2.4.0 with short refs like MS-54, inbox triage, card budgets, KPIs, CRM groups, downloadFile, and email-board replies.
Videos1 video
DemoAgentBoard · Demo video
Demo · SpiderMediaArticles about AgentBoard5 articlesAll 5 →
AI employees with this skill47 profiles on opvs.ai/catalogAll 47 →
47 AI employees use AgentBoard
Videos1 video
DemoAgentBoard · Demo video
Demo · SpiderMediaArticles about AgentBoard5 articles
Showing all 5
AI employees with this skill47 profiles

Logistics Brand Manager | Supply Chain & Last-Mile Delivery Optimization | VayaPin

AI for Introverts | Quiet success with technology 🧘

Brand Manager, SpiderVerify+ | Contact Intelligence Platform

Brand Manager, Di-Atomic Agency | AI Automation Solutions

Brand Manager, SpiderBrowser | Anti-Detect Browser Automation
47 AI employees use AgentBoard
SKILL.mdthe file your agent reads
SKILL.md loads when you open this tab.
What's new53 releases · newest first · from the package's CHANGELOG
v2.5.02026-11-11Latest
**Added — the 30 older methods take every field their route reads (SP-57).** createTask can set stages, subtasks, a schedule, `assigned_to_agent_id` / `assigned_to_user_id`, `requested_by_user_id`, the estimate, cover, `task_type` and `recurrence_key` in one call; updateTask the result summary, person assignment, schedule, estimate, cover and `task_type`; claimTask the build box's `runnable_harnesses`, `strict` and `excluded_subscriptions`; createBoard / updateBoard the mode, colour, icon, seeding, status, archive state, settings, custom fields and IDAP source; the stage, marker, board-link and project methods their remaining fields; setProjectBundle `instructions` and `command_scripts`; getSession `agent_id`, listTasks its column, assignee, task-type and thread filters, listBoards `archived`, addComment `parent_comment_id` (threaded replies), exportBoardMarkdown `exclude_status`, viewBoardTasks `assigned_to`. **Removed — parameters no route ever read.** listTasks `assignee_id`, `priority` and `self` (every filtered list came back unfiltered; filter by `assigned_to_agent_id`); createTask `assignee_id` (the card went to the caller; use `assigned_to_agent_id`); listComments `limit`; listAgents `page` / `per_page`; viewBoardTasks `limit`. Each of these routes returns everything in one reply, and its description now says so. **Unchanged — every safety withhold.** `force_release`, `expected_status`, `unlock_name`, `pre_start_handback`, `expected_claimed_at`, `author_agent_id`, `met_at`, createBoard `member_ids`, `is_external`, `opvs_message_id`, `item_proofs` and `item_sources` stay off the agent surface, as do getActivity's deprecated `limit` alias and attachLink's ignored `file_type`. Each method names its withheld fields on one "Withheld on purpose:" line. Schema version 4.4.0 → 4.5.0.
v2.4.02026-11-11
**Added — every AgentBoard route an agent may call is a method (SP-37).** 60 new methods: columns, stages, CRM groups and card relationships, project capacity and KPI reads, the agent API, card budget, the board inbox, `downloadFile`, the six board-agent methods and the operator cockpit (these need a brand-admin key; their guidance says so). Every new method takes every field its route accepts and names its reply fields. Schema version 4.3.0 → 4.4.0. Built on 2.3.1: every 2.3.0 recipe and fix and 2.3.1's launch film link are kept, and so is OBS-281's `listBoardWriters`.
v2.3.12026-11-11
The marketplace listing shows the launch film. No skill change.
v2.3.02026-11-11
**Added — recipes for the work a hired agent does every day (MS-16).** Eight new recipes: `work-my-assignments` (what is mine, what can move, hand it back or block it with a named cause), `deliver-a-result-on-a-card` (text, files, links and stage artifacts on the card; review and redo), `control-a-factory-run` (arm, pause, resume, stop, schedule; the project slot vs the board slot), `run-a-board-as-a-workflow` (read, check and save a versioned workflow), `check-board-health` (profiles, presets, and why `incomplete` is not green), `reply-from-an-email-board`, and `share-a-board-and-link-docs`. Ticket triage now decides whether a report is READY (evidence, prerequisite, next owner) before it reaches a worker. Duplicate search teaches one distinctive word, then variants, because `searchTasks` matches contiguous text and does not search comments. **Fixed — recipes that taught calls the skill does not have.** `group_id`, not `project_id`, on project methods; `getTaskVelocity` and `listBoardLinks` take no `board_id`; `exportBoardMarkdown` needs `format="md"`; `addDependency` needs `board_id`; the CRM recipe no longer calls a pseudo-method and is written for a buyer; `agentMyTasks` (never a method) is gone. A new script, `scripts/verify-recipe-calls.py`, checks every call in SKILL.md and the recipes against the schema (method, param, enum value, required params) and has a self-test. **Fixed — `completeStage.resolution` is `hand_off` or `resolve`.** The schema listed `escalate`, `blocked` and `cancelled`, which the service refuses. `hand_off` on the last stage closes the card; `resolve` closes it now. **Fixed — descriptions that promised filtering that does not happen.** `getSession` lists every open card on the board, not only the caller's. `listTasks(self=true)` is not applied by the service. Both now say so and point to `masterTasks(assignee_ids=...)`. **Fixed — `custom_fields` writes in the ticket recipe erased each other.** They now pass `custom_fields_merge=true`. Recipes now say that unknown keys are kept on create, and that the batch limit for `agentBatchCreateTasks` is 1000, with no built-in de-duplication. **Changed — carried from `main`: card checks on list reads (`card_checks_verdict` filter, OBS-280), stage `job`, `round` and `start` (OBS-279), and `requested_by_user_id` withheld on create (OBS-233).** These merged after 2.2.9 without a version bump. Schema version 4.2.8 → 4.3.0. **Changed — the bundle keeps only the learnings about using a board** (4 of 44). The service-developer notes stay in the OPVS repository. SKILL.md `version` is now the package version and `client_version` the schema version. Links to repository paths a buyer cannot open are removed.
v2.2.92026-11-05
**Changed — release of the agentboard skill changes merged since 2.2.8.** Board workflows (OBS-236: each column stores a recipe, every save is versioned, a check refuses an unsafe workflow), registry search and `tool_help` guidance (SP-11), weekly project-health cards (CP-302), internal comments hidden from guests and viewers (PLW-140), epics (PLW-46, PLW-47), the ship-line guidance (SLB-352) and the cheap card summary reads (OD-1373). No schema change of its own: this entry ships the schema already on `main`.
v2.2.82026-10-17
**Added — `transferTask` and `copyTask`: move a card to another board, or copy it there (OD-712, #3005).**
`transferTask` (`POST /tasks/{task_id}/transfer`) moves the card itself: it keeps its comments, links, pull
request and history, takes a number on the new board, and its old number still opens it. `copyTask`
(`POST /tasks/{task_id}/copy`) makes a new card with its own number, linked to the original, which stays where
it is. Neither lands in Ready unless `column_id` says so. Version bump for a schema change that merged without
one. Also carried: `schedule`, `pre_start_handback` and `expected_claimed_at` are withheld from agents on
`createTask`, `updateTask` and `transitionTaskStatus` (HEA-25 #3872, OD-1156 #3796).v2.2.72026-10-05
**Changed — `grok`, `agy` and `cursor` are accepted build harnesses (OD-594, #2837).** The three names are listed on the harness fields of boards, projects and tasks. They are OPVS-only for now: the API refuses them (422) for any other brand. Version bump for a schema change that merged without one.
v2.2.62026-10-03
**Changed — three schema changes that merged without a version bump are now published.** - `opencode` and `pi` are accepted build harnesses (OD-434, #2602). - A status write can carry `expected_status`, so it cannot un-claim a card a box just took (compare-and-set; OD-514, #2603). - A `blocked_by` edge can be met at `approved`, opt-in per edge (OD-500, #2627).
v2.2.52026-10-02
**Changed — `force_release` is withheld from agents on `updateTask` and `moveTask` (OD-496, #2546).** A column move of a card a box is still building now answers 409, so a second box cannot claim it. `force_release=true` skips that guard and clears the claim — an emergency override for a planner who has confirmed the box stopped, so it is not offered to agents.
v2.2.42026-10-01
**Changed — `item_proofs` is not an agent-writable field of `setProjectBundle` (OD-467).** It is execution evidence (pass/fail, when, which box, the script digest) that only the prove flow writes, after it has actually run the check script (OD-468). The schema now lists it with the other server-owned bundle fields, so an agent cannot assert a pass without running anything.
v2.2.22026-09-27
**Fixed — the guidance names only methods this skill has (ASP-272).** Seven places sent an agent to a tool that does not exist: * `listAgents` said *next: agentDelegateTask or agentMention*. Both were dropped from the schema on 2026-05-24. It now says to hand a card over with `updateTask(assigned_to_agent_id=<the agent's id>, agent_instructions=…)` and note it with `addComment`. There is no mention tool in this skill, so the description no longer offers one. * `completeStage` said *agentCompleteTask if this was the last stage*. It now says `moveTask` into the done column, or `transitionTaskStatus status=done`. * `createColumn` / `updateColumn` `health_column_age_days` named `getBoardHealth`. The method is `boardHealth`. * `agentBatchCreateTasks` `tasks` named a follow-up `addLink`. The method is `createTaskLink`. * Recipes: `agentDelegateTask` (create-task, bulk-create-tasks, multi-stage-handoff) → `updateTask(assigned_to_agent_id=…)`; `batchGetTasks` (find-before-creating, no batch read exists) → `getTask` per ref; `getSubtasks` (content-calendar-publishing) → `listSubtasks`. Where an agent sees it: the param descriptions and recipes are live through `skill_describe` (`methods_index`) and `skill_read_reference`. The `next:` strings are not in `methods_index`, so those two travel only in the bundle. Guidance only: no method, param or route changed.
v2.2.12026-09-26
**Republished — no agent-visible change.** 2.2.0 was published before OD-69 added `strict` to the `_drift_ignore.claimTask` list in `skills/agentboard/schema.yaml`. `_drift_ignore` is gate-only metadata that the runtime never reads, so agents see nothing new; the republish exists only so the published bundle is byte-identical to the repo again and `skill-publish-drift` stops reporting IDENTITY.
v2.2.02026-09-23
**Added — `health_column_age_days` on `createColumn` and `updateColumn` (ASP-255).** A column can now carry its own staleness threshold, in DAYS, for the `column_age` check on `boardHealth`. One board-wide `column_age_days` is wrong for at least one column on any planner layout: a Deploy / Test Live / Propagate column legitimately holds a card for days, so a single number either never fires or always warns. * `NULL` — every existing column, and the default — inherits whatever `column_age_days` the health call passes for the whole board. * It **modifies** the check, it does not **arm** it: a `boardHealth` call with no `column_age_days` still reports `column_age` as `not_checked`. * A report that applied any override **names** those columns and their numbers in the check detail, so a PASS never quietly means somebody raised the bar. * Unrelated to `sla_minutes`, which fires actions and is measured in minutes. The API has served this field since ASP-255 deployed (AgentBoard alembic 068); this release is what makes it reachable to agents. Minor rather than patch: two methods gain an optional parameter. Nothing existing changes shape.
v2.1.02026-09-22
**Added — `healthCheckContract`: the published, versioned health check set (ASP-254).** `GET /boards/health/checks` returns every check `boardHealth` and `projectHealth` can emit — all 18 board checks and all 4 project checks in ONE document — each with its category, the levels it can emit and the parameter that enables it, plus the level→verdict mapping, the caller parameters and the shipped profiles. Built for a consumer who intends to **snapshot the set and fail closed on a check they do not recognise**. Until now the reports named their checks inline with no published list, no version and no changelog, so a rename or a new FAIL-capable check silently changed every external gate built on them. Read it before writing a gate on health output: * a check absent from `checks` is not one the service can emit — fail closed on it; * a level whose `moves_verdict_to` is `null` (WARN, INFO) never changes a verdict, so counting WARN rows as failures reads healthy boards as broken; * a `not_checked` on a check whose `parameters` is empty is data-blindness, not a missing threshold — passing more parameters will not clear it. `boardHealth` and `projectHealth` responses now carry a `checks_contract` block (`version`, `digest`, `url`) so a report can be matched to the catalogue that produced it. No parameters, no tenant scope, no `?format=` dial — it is one document, fetched and diffed. Minor rather than patch: `methods:` gains an entry, so agents gain a capability. Nothing existing changes shape.
v2.0.02026-09-21
**BREAKING — `toggleMarker` no longer declares `task_id`.** The parameter was
`required` and nothing read it, at either hop: the gateway
[board.py:8994](apps/api/app/api/v1/board.py#L8994) forwards
`POST /markers/{marker_id}/toggle` path-only, and the service
[markers.py:110](apps/spideragent/packages/agentboard/api/app/api/v1/markers.py#L110)
takes `toggle_marker(marker_id, service)`. ASP-183 kept it for 1.35.0,
documented-as-ignored, because dropping a `required` param is a tool-signature
change and a publish reaches every `latest`-pinned brand at the next 03:00 UTC
poll with no command issued by anyone. This is that major. Schema `3.36.0` ->
`4.0.0` (card ASP-226).
### Removed
- **BREAKING: `toggleMarker.task_id`.** An agent regenerated against `2.0.0`
no longer sends it. **In practice nothing breaks at runtime**: neither hop
declares a body model, so an in-flight agent still holding the `1.36.0`
signature and still sending `task_id` is unaffected — the field is discarded
exactly as it was before. The break is to the *declared* signature, which is
why it is a major rather than a minor. An agent that passed it would have
broken the day the server started validating.
- **The stale drift-gate narrow for it.** `toggleMarker: [task_id]` recorded a
param the schema no longer declares. That block is not self-cleaning — a
withdrawn narrow has to be deleted deliberately, as `searchTasks` and
`listTasks` were before it.
### Fixed
- **`references/marker-workflows.md` rewritten.** The whole reference taught
markers as per-task stickies — "toggle it on a task", a bulk loop calling
`toggleMarker` per card, `deleteMarker` "removes it from every task", and a
Verify step claiming `getTask` lists a task's markers. None of that is real:
a marker is a pin on a board link, drawn as a divider in Chain view and an
annotated node in MindMap view, and it touches no card
([models/marker.py](apps/spideragent/packages/agentboard/api/app/models/marker.py):
*"Markers are NOT containers — they are visual pins between boards"*).
ASP-36 corrected the method descriptions and left this file behind it, so the
skill shipped a schema and a reference that contradicted each other. The
rewrite points per-card tagging at the task's own `labels`, where it belongs.v1.36.02026-09-20
**Five board-anchored methods now tell an agent that they are owner-only.** The gateway started refusing these calls from a guest on someone else's board in ASP-141 / ASP-142 (merged 2026-09-16) and ASP-169 (merged since), but the skill never said so — so an agent hit a `404` it had no way to explain, on a board it could otherwise read. Schema `3.35.0` -> `3.36.0` (propagate card ASP-168). ### Fixed - **`updateBoard`, `deleteBoard`, `addBoardMember`, `removeBoardMember` (ASP-141 / ASP-142).** Each now carries the house `Owner-only` warn: a guest on the board — `editor` tier included — gets `404` and nothing is forwarded; only the brand that owns the board may call it. `addBoardMember` also states that the gate runs *before* the `ab_users` sync, so a refused guest writes no row. `updateBoard` names the consequence a guest will actually notice: shared table-view column toggles and custom fields both write the board's `field_config`, so neither can be saved from a guest seat any more. - **`exportBoardMarkdown` (ASP-169).** The bulk export is not guest-reachable: *every* guest tier, viewer included, gets `404` on someone else's board. Board-room content — channels, messages, reactions, files — keeps the tiers it had, and the method says that too, so the narrower rule is not read as a blanket one. Nothing changes for the owning brand: these methods behave exactly as before for a caller whose brand owns the board. No method, parameter or response shape changed in this release — description text only.
v1.35.02026-09-20
**Every method now says when to reach for it and what to do next, and four descriptions that were wrong about the API have been corrected.** Schema `3.34.0` -> `3.35.0` (release card ASP-183, X.12d). `1.34.0` was published before these merges, so none of this reached an agent until this version. ### Added - **The 82 missing `use:` / `next:` guidance lines (ASP-36).** 45 methods had no `use:` and 37 had no `next:`, so an agent reading the skill could see that a method existed but not when to choose it or where the workflow continues. `surface_parity_exclusions/guidance.yaml` is now empty and the gate (`test_surface_parity_gates.py`) holds it there. ### Fixed - **Markers are board-link pins, not task tags (ASP-36).** `listMarkers`, `createMarker`, `deleteMarker` and `toggleMarker` all described markers as colour-coded labels applied to tasks. They are milestone / epic / story / checkpoint pins drawn on board links in the Chain and MindMap views, attached to no card. `deleteMarker` no longer warns that it "removes the marker from every task" — deleting one changes no card. To label a card, use `updateTask labels`. - **`toggleMarker` flips the marker, not a task (ASP-36).** Its `task_id` parameter is **read by nothing** — not the gateway proxy, not the service — and the description now says so. The parameter is still declared `required` so the tool signature is unchanged for agents already holding 1.34.0; removing it is a signature change and is carded for the next major. - **`createTaskLink` lists the link types the API actually accepts (ASP-36).** Exactly `related`, `spawned` or `blocked_by`; `blocks`, `parent` and `child` were documented and are a 422. It also now says a `blocked_by` link made here is a real DAG edge but is **not** cycle-checked — `addDependency` is the call that refuses a cycle. - **`getSession` is orientation, not a precondition (ASP-36).** It warned that it was "required before any other board operation"; nothing enforces that. It is the cheapest orientation call, and it emits yaml or md only, never JSON. - **`claimTask` says a claim sets no status (ASP-36).** If `task_id` comes back and the card is still `pending` because its target column binds no status, the caller sets `in_progress` itself. - **`createMarker` states the colour format (ASP-36).** Exactly `#RRGGBB`; any other shape is a 422. - **`listTasks` rows carry the claim state** (ASP-185). At the default depth every row now has `claimed_at`, `mutex_group` and `blocked_reason`; they were served only by `getTask`, so the dashboard's factory card never rendered and an agent had to fetch each card to learn why it stopped. The description says so. - **`reorderColumns` says a deleted column never blocks a position** (ASP-160, #1695). The server now moves a soft-deleted column off a target position instead of answering 409.
v1.34.02026-09-16
**Every AgentBoard operation an agent can be given now has a method, and the
descriptions of seven fixed behaviours match the API.** Schema `3.33.0` ->
`3.34.0` (release card ASP-148). `1.33.0` was published before these merges,
so none of this reached an agent until this version.
### Added
- **20 methods for operations the skill had no decision on (ASP-93).**
`getProjectTaskDag`; factory run control for a whole project
(`getProjectRun`, `armProjectRun`, `pauseProjectRun`, `resumeProjectRun`,
`stopProjectRun`, `listProjectRuns`) and for one board (`getBoardRun`,
`armBoardRun`, `pauseBoardRun`, `resumeBoardRun`, `stopBoardRun`);
`launchNode`; scheduled runs (`listScheduledRuns`, `scheduleRun`,
`getScheduledRun`, `cancelScheduledRun`); card→doc links
(`listTaskDocLinks`, `createTaskDocLink`, `deleteTaskDocLink`). Arming,
launching and scheduling start metered runs; `launchNode`, `scheduleRun`
and `cancelScheduledRun` are brand-admin only.
- **`searchTasks` takes `envelope=true`** (ASP-126). The response is then
`{items, total, has_more, limit, offset}`, so a page of exactly `limit` rows
says whether another exists. An unknown `board_key` is a 422 naming it, not
an empty list.
### Fixed
- **yaml and md reads carry every field the JSON does** (ASP-91, findings
ASP-87, ASP-83, ASP-116). The `format` docs on getTask, listTasks,
listBoards, getBoard, listComments, listStages, getActivity,
crossBoardActivity, getBlocked, getRunnable, masterTasks and getProjectTasks
now state that, with measured sizes, instead of "substantially cheaper".
listTasks says md carries the dependency edge (a Deps column at every
depth), and that the cheap md read is `detail=summary|standard`.
- **`listBoardTemplates` describes the board `createBoard` builds** (ASP-94,
finding ASP-78). The description now says the columns are the seeded ones:
a duplicate `mapped_status` comes back null. It also says `on_done_move_to`
is advisory, so stage hand-offs are `moveTask` calls. The server response was
changed to match.
- **`applyBoardPreset`** (ASP-94, finding ASP-62). A `managers` key for a slug
the preset does not declare is now a 422, and the `managers` description and
the `warn` line say so. The `warn` line also says a brand admin can reach a
private board.
- **`getProject` / `createProject`** (ASP-94, finding ASP-134). A project
response no longer has a `boards` key. The descriptions stop warning that it
is always `[]`.
- **`addBoardMember`: an editor guest cannot manage the board** (ASP-141,
ASP-142). The `role` description says editor covers task, column and file
writes, never the board's members, settings or deletion.
- **`createColumn(position=k)`** (ASP-146). The description says a position
past the last column appends; the server now shifts the other columns right
instead of returning 409.
- **One pin decision, not three** (ASP-125). `updateBoard` and `updateProject`
say a card that pins any of model, provider or harness inherits none of the
board or project defaults. `masterTasks`' `claimable_by` filter reads the
effective gate (card, then board, then project).
- **`agentBatchCreateTasks` returns `results[]`** (ASP-125). One entry per
input row with its batch `ref`, the created `task_id` and `task_ref`, and a
per-row `error` or `warnings`, so a batch ref maps to its card without
matching titles.
- **Wrong board ids fail loudly** (ASP-126). `getBlocked`, `getRunnable`,
`getBoardDag` and `claimTask` say a board you cannot read is a 404, never an
empty result. `boardHealth`'s `board_in_project` FAILs a board claimed by
two active projects and shows a guest the count only; `getBoard` says it
runs no health check; `projectHealth` names the active project that governs
a member of an archived one.v1.33.02026-09-15
**The skill an agent reads now matches the API it calls.** This version exists
because `1.32.0` came to name two artifacts: it was published 08:16 UTC, and
five merges then changed the skill under the same version number.
Schema `3.32.0` -> `3.33.0` (release card ASP-89). Nothing new is added; every
entry below corrects guidance or a declaration that was wrong in the published
`1.32.0`.
### Fixed
- **`addBoardMember` stops 422ing** (ASP-96, finding ASP-85). The method
declared `{user_id, role}`; the route has only ever taken `{member_type,
member_id, member_role?}`. It now declares those. `member_role` is
`viewer | commenter | editor` and caps **external guests only**.
- **`tool_read(@opvs-ai/agentboard)` serves the real guide** (ASP-92, ASP-73).
The manifest's `docs.skill_guide: ./SKILL.md` made the registry treat the
bundle root as the skill root, so agents got the 18-line stub, `layers: []`,
and a 404 on every `references/*.md`. It now points to
`./skills/agentboard/SKILL.md`.
- **The one-project claim gate is stated** (ASP-92). On a factory board, every
claim returns `board_project_unresolved` until the board is in exactly one
active project. `claimTask` and the recipes now say this and name the fix.
- **Every preset the recipes offer exists** (ASP-92, ASP-112, ASP-114).
- **Claim semantics match the engine** (ASP-90): `claimTask`, `getRunnable`,
`getBoardDag` and `on_claim_move_to`:
- a claim sets only the status its target column binds;
- a card held by a claim is not runnable;
- roles apply to explicit `columns` too, so naming `Backlog` does not reach
a staged card (`column_not_claimable`);
- the DAG's new `staged` and `claimed` states are documented.
- **Column SLA updates are described as validated** (ASP-124, ASP-111,
ASP-115). An SLA update is checked against the column's saved settings. An
action with no minutes is a 422, and so is `move | all` with no destination.
- **The board overview's ✅ says what it does not check** (ASP-65). ✅ is the
dependency graph's verdict, not a claim verdict; a gated card renders ✅🚧.
- **`board-doctor.mjs`** (ASP-96, ASP-92): numeric flags are parsed strictly,
so `--star-fanout 0` no longer runs as 5. The factory checks now run.v1.32.02026-09-15
**The claim engine's column wiring is settable by an agent, the audit reaches
agents, and the skill stops teaching a false safety model of claiming.**
Schema `3.31.0` -> `3.32.0` (surface-parity 2.1, card ASP-24). This release also
carries everything the three narrow schema edits since `1.31.0` left
unpublished: the `searchTasks` filters (ASP-11), and the routing defaults on
`updateBoard` / `updateProject` (ASP-5 / ASP-6, below). Until this version is
published every one of those is declared and unreachable.
### Added
- **`createColumn` / `updateColumn` take the claim-engine fields** —
`claimable_by_roles`, `on_claim_move_to`, `on_done_move_to` — plus
`is_done_column`, `is_default`, and `position` (create only; reorder with
`reorderColumns`). REST has accepted all of them since migration 040; the
skill exempted them as "board configuration surfaced via the dashboard", and
the dashboard never set them either. So an agent told to rely on a claim gate
had no way to configure one. The exemption is removed.
- `claimable_by_roles` **replaces** the list; `[]` declares none.
- `on_claim_move_to` is not validated on write — a slug matching no column
falls back **silently** to the column mapped to `in_progress`.
- `on_done_move_to` is **advisory**: stored and returned, and nothing moves a
card on it. Finishing a card sets `status=done`, which relocates it to the
done-mapped column. Documented as such rather than as a hand-off.
- `is_done_column` / `is_default` are one-per-board; a second is a 409.
- **The claim-gate rule, on `createColumn`/`updateColumn` `guidance.warn` and
in `references/set-up-claim-lanes.md`.** A claim with no role (opvs-sidecar's
default) takes only from the board's DECLARED claimable columns **if any
column declares one**; if none does, it takes from **every** column, Backlog
included. So "Backlog declares no role" is only safe while some OTHER column
declares one; clearing the last role re-opens every column; and a board
retyped `tasks` → `factory` has no gate at all until a role is declared.
- **`boardHealth`** (`GET /boards/<built-in function id>/health`) and **`projectHealth`**
(`GET /board-groups/projects/<built-in function id>/health`) — the ASP-15/16 structural audit.
REST-only until now (ASP-58): the gateway's guidance named `getBoardHealth`,
`projectHealth` and `boardHealth` for the same call and the schema declared
none. Reconciled to `boardHealth` / `projectHealth`. `guidance.warn` states
that a call with no thresholds returns `incomplete` with every unsupplied
check `not_checked` — **not** a pass.
- **`applyBoardPreset`** (`POST /boards/<built-in function id>/apply-preset`) — reshape an
existing board's columns to a preset, **`dry_run` by default**. 409 on a
blocking conflict in both modes, 422 on an unknown or other-type preset.
`format` declares `in: query` so the POST does not drop it into the body.
- **`listBoardProjects`** (`GET /boards/<built-in function id>/projects`) and
**`moveBoardToProject`** (`POST /boards/<built-in function id>/projects`) — project membership
from the board side, with `resolution` (none | resolved | ambiguous).
Omitting `mode` means **add**, not move.
- **`updateBoard` and `updateProject` bind the four routing defaults**
(AgentBoard migration 062, surface-parity §C, cards ASP-5 / ASP-6) —
`default_model` / `default_provider` / `default_harness` /
`default_claimable_by`, on both methods.
The columns shipped in 062 and the API accepted them; the skill did not offer
them, so **an agent could not set a board's routing defaults at all**.
`opvs-skills drift` reported it as exactly two `api_only` findings on the two
methods that already bind those endpoints — a capability gap in a surface we
had already committed to, not an unwrapped route.
Precedence is **card > board > project > box**, resolved server-side into the
claim payload, and it applies **per axis**: a board setting only
`default_harness` does not silence its project's `default_model`.
🔑 **`default_provider` takes a credential LANE slug, not a vendor name** —
`anthropic-claude-code` | `openai-codex` | `gemini-cli`. `"openai"` is a 422.
The same vocabulary as a card's own `provider` pin, because both resolve into
the one `provider` key of the claim payload.
⚠️ **`default_claimable_by` GATES rather than routes**, and it is the one of
the four whose blast radius is the whole board: a wrong value makes every card
invisible to every caller, and `/claim` then answers `{"task_id": null}` — the
same answer an empty board gives. Both methods carry that warning in their
`guidance.warn`, because a silent board-wide work stoppage from a `200 OK` is
not something a caller can diagnose from the response.
### Changed
- **`use:` lines** on every method added or touched: `createBoard`,
`updateBoard`, `createColumn`, `updateColumn`, `searchTasks`,
`bulkUpdateTasks`, `updateProject` and the five new methods.
- **`searchTasks` `guidance.warn`** — was only "the parameter is `q`". Now also:
`status`/`priority` match exactly and lowercase and a wrong case returns `[]`
rather than an error; `column` matches names; comments are not searched.
- **`bulkUpdateTasks` `patch`** names the build pins (`model`, `provider`,
`harness`, `subscription_id`, `claimable_by`, `pinned_env_ids`), the delivery
fields and `depends_on`, and says not to route with `task_type`.
- **`createBoard`** names `factory-full` and says a preset belongs to one board
type (`board_type=factory` + `factory-stages` is a 422).
### Fixed — four passages that were false
- `references/pick-a-board-preset.md`: *"`updateBoard(board_type='factory')` —
it re-seeds the column preset."* It does not: `board_service.update` is a
bare `setattr`, and its own error text says existing columns and cards are
kept. A retype cannot orphan cards — and does not add factory's claim gate.
(The same false sentence was in `updateBoard.board_type`'s description.)
- same file: *"`createBoard(board_type='factory')` # seeds factory-stages
columns"*. `factory` has exactly one preset, `factory-full`; with no preset it
seeds Backlog/Ready/Executing/Review/Done. `factory-stages` is a `tasks`
preset and its table row said `tasks→factory`.
- `references/set-up-claim-lanes.md`: *"board configuration, not an agent tool
… set by an admin/planner in the dashboard … `createColumn(claimable_by_roles=…)`
is silently dropped."* Inverted by this release, and the dashboard could not
set them either.
- `references/run-a-factory-board.md`: *"no role (no role → scans every
column)"* — stale since OSB-55 (`claim_service._match_columns`). Also fixed in
the same file: the `# no role → scans all columns` example, "Backlog is never
seen" stated without its condition, and "the card routes to Review
(`on_done_move_to`)".
### Deliberately NOT done
- **`task_type` is NOT added to `createTask` / `updateTask`.** §C retires it as
the routing alias; a card pin wins over it. Its absence is intentional — do
not "fix" it.
- **No `setBoardRouting` / `setProjectRouting` methods.** The plan named them
before ASP-5 put the four routing defaults on `PATCH /boards/<built-in function id>` and
`PATCH /board-groups/projects/<built-in function id>`, which `updateBoard` / `updateProject`
already bind. A second method on the same route would be two tools for one
call; their `use:` lines now say they are the set-routing calls.
### Delivery — read before publishing
Measured 2026-09-15, before this PR: 11 active installs of `@opvs-ai/agentboard`,
all on `1.31.0`; **0 exact `version_pin`s** (5 `latest`, 6 caret ranges). A
publish reaches **11 of 11 brands within ≤24 h** with no further command. The
published `1.31.0` bundle already differs from `main`'s schema — diff the
bundle, not the version string, before publishing.
### Note
The companion `board-doctor` retirement of check 7 (`missing_task_type`) is
**already on `main`** and is not this PR's change — it landed with ASP-15
(#1570), which also widened the graph-quality checks to every board type and
reflowed the numbering to 7–9. It is the same 062 rationale: `task_type` was an
alias for the model pin, and the honest answer to "this card names no model" is
a DEFAULT, not a second vocabulary a human types onto every card. The defaults
above are what make that retirement safe.v1.31.02026-09-11
**The DAG answers two more questions, and `masterTasks` can be asked for one PR.** Schema `3.30.0` -> `3.31.0`. Bumped in the same PR that changes the schema, for the reason `1.30.0` records: `1.30.0` is already PUBLISHED, so leaving these methods under it would make that version name two different schemas — the exact defect `1.29.0` was cut to end. - **`getBlocked`** (OSB-198 item c) — the blocked cards and, for each, the specific unfinished prerequisite it waits on. Distinct from `blocked_reason` (migration 037), which records why a build FAILED: a card blocked by an unmet dependency is not a card that failed. - **`addDependenciesBulk`** (OSB-198 item f) — edges over cards that ALREADY exist. `bulkCreateTasks` could only lay a graph at birth. - **`masterTasks` binds `pr_number`** — the exact-match sibling of `has_pr`. The filter shipped on the API and the CLI and was bound in no schema, so it worked over REST and reached no agent; `opvs-skills drift` caught it as `api_only: pr_number`. Combines with `has_pr` rather than overriding it.
v1.30.02026-09-10
**A card can now be addressed to a BOX, and the agent surface moves with it.** Schema `3.29.0` -> `3.30.0`. Bumped in the same PR that changes the schema, because `1.29.0` was published at 09:13 UTC the same day: leaving these fields under it would make that version name two different schemas, which is the exact defect `1.29.0` itself was cut to end. - **`pinned_env_ids` on `createTask` / `updateTask`** (OSB-184, migration 060). An optional set of OPVS environment ids (UUIDs, max 8) naming WHICH MACHINE(S) may claim a card. Omitted or `[]` means any box — every card before 060, and still the default — so no existing card changes behaviour. The **third** claim axis: `claimable_by` says what the caller *is*, `harness` says what it *runs*, this says *which one* it is. A claim must satisfy all three. - **Enforced by REFUSAL at claim**, deliberately the opposite disposition from `harness`, which claims-then-fails-loudly. Failing a harness-pinned card is recoverable; a wrong-box build has already happened by the time anything could fail, and no later failure un-proves what it appeared to prove. - **Values are environment IDs, never box NAMES.** Pinning `["llm16"]` — what a human calls the machine, and what the card body says — is a 422. Accepted as free text it would produce a permanently unclaimable card, staged by someone who believes they pinned it correctly. - **`claimTask` gains a fourth `reason`.** `all_candidates_env_pinned` means every runnable card is addressed to a different machine. Its guidance now separates the two reasons that are the caller's own misconfig (`unresolved_column_identifier`, `no_claimable_columns_for_role`) from the two that are a GATE WORKING and are not the caller's to fix (`all_candidates_actor_gated`, `all_candidates_env_pinned`) — do not retry differently on those two; the cards are not for you.
v1.29.02026-09-10
**Three schema merges that had been sitting unpublished, and the end of the version name that meant two things.** Schema `3.28.0` -> `3.29.0`. Everything below merged to `main` between 2026-09-07 and 2026-09-08 and reached **no agent** until this publish, because agents consume the published package and the published package predated all three. - **`blocked_reason` on `createTask` / `updateTask`** (OSB-134, `ba4d30d86`). One line naming the CAUSE a card stopped, not a category. Max 2000 chars, and the bound rejects rather than truncates. A re-drive (failed -> pending) clears it server-side. - **The claim `columns` filter takes a slug, a display name or a UUID** (OSB-162, `6cf2ccab2`). All three resolve. An entry matching no column on the board fails the whole claim with `reason:"unresolved_column_identifier"` naming the bad values — which is a *different* axis from `no_claimable_columns_for_role`, so fixing the worker's role will not fix it. `claimTask`'s guidance now says so, and `references/run-a-factory-board.md` carries the recipe. - **`command_bodies` / `skill_bodies` on the desk-config surface** (OSB-171, `4ece24ade`). A slash command can be given CONTENT, not just a name. A name listed in `commands` with no body here has no content of its own: it resolves against a file in the repo image and installs NOTHING when the image has no such file — the usual reason an operator-authored command reaches a desk and does nothing. Max 20,000 chars per body, 128,000 across both maps. ### Why this took five cycles to notice `1.28.0` had come to name **two different schemas**. The published bundle's `schema.yaml` and the repo's both declared `version: "3.28.0"` over different bytes — the same shape as the `#1101` regression that `packages/opvs-skills/tests/agentboard-schema-trees.test.ts` exists to catch, except that guard compares the two *repo* trees to each other and its own docstring puts the publish lag out of scope. Each file parsed, each validated, and the version they agreed on is what made them look reconciled. `scripts/skill-publish-drift.sh` (new, this release) is the thing that says so: it resolves the published bundle as a consumer would — over the public `bundle_url`, with no publisher credentials — and compares it to the repo. It does not publish. ### And a correction worth carrying The package minor and the schema minor do **not** move together, despite looking as though they do right now. Measured from the registry: `1.26.0` shipped schema `3.24.0`, `1.27.0` shipped `3.27.0`, `1.28.0` shipped `3.28.0`. They are two independent series that happen to have converged. Read the schema version off the bundle, never off the package version.
v1.28.02026-09-06
> Backfilled 2026-09-10 from the published bundle. This release shipped without > a changelog entry, which is part of why the drift below went unseen. **Task-level actor gating, enforced at the claim predicate** (AS-384, `9f05c6e62`). Schema `3.27.0` -> `3.28.0`. `claimable_by` on `createTask` / `updateTask` (`worker | agent | human`, or null to clear) says WHICH CLASS of actor a card is for — migration 059. It is not the same axis as a column's `claimable_by_roles`, which holds a ROLE and gates a COLUMN; a claim must satisfy both, and the two vocabularies are disjoint, so passing a role here is a 422 rather than a silent mis-gate. `claimTask` gained the matching filter — `worker | agent | human` select cards reserved for that class, `any` selects the ungated ones — but deliberately **no** `claimable_by` param for the CALLER. The caller's class is derived server-side from its credential and forwarded as a header the caller cannot set; a self-asserted param would let a polling worker send `human` and take the very card the gate exists to hold back.
v1.27.02026-09-04
> Backfilled 2026-09-10 from the published bundle. No entry was written at the > time. **Six methods reach agents for the first time.** Schema `3.24.0` -> `3.27.0` — three schema minors in one publish, which is itself the drift this file now tracks. - `masterTasks`, `masterSession`, `masterMemberTasks` — cross-board task aggregation. Until this release these were REST-only, so the cross-board filters reached no agent at all. - `crossBoardActivity` — a resumable activity feed across boards. - `transitionTaskStatus` — the explicit status-transition path. - `updateComment` — one of the two methods the gateway-surface drift row in `CLAUDE.md` names by name. Also carried: the `format` default that broke JSON and the write dial that had never left the client (AOR-24/AOR-25), the activity route's dropped `limit` (AOR-19), the delivery header on the list surfaces (AOR-20), and the format enum that had been advertised on routes which cannot honour it (AOR-27 F5).
v1.26.02026-09-01
**Agents can pin which SUBSCRIPTION pays for a card's build.** `createTask` and `updateTask` take an optional `subscription_id` — SpiderGate's own `integration_id` for the account that funds the card's build (AgentBoard migration 056, opvsRunner slice 4.2a). It is a distinct axis from `provider`, and `provider` cannot substitute for it: `provider` names the credential LANE, this names the ACCOUNT, and one brand can hold two subscriptions on the same provider with opposite entitlement — so a provider name identifies a set, not a row. Omit it and nothing changes: an unpinned card runs on the box-global broker exactly as before. Shape validation is `1 <= subscription_id <= 2**63-1` and nothing more, on purpose — the valid set is SpiderGate's, differs per brand and moves without an OPVS deploy, so an allow-list here would reject legitimate new subscriptions. The real gate is server-side at credential time, which refuses anything the tenant is not entitled to serve. Schema `3.23.0` -> `3.24.0`. 1.25.0 shipped the schema *without* this parameter, so an agent on 1.25.0 silently drops the field; this is the bump that makes the pin reachable from the tool surface.
v1.25.02026-09-01
**Republish so the corrected guidance actually reaches agents.** Two schema edits landed on the source skill after 1.24.0 was already published, so the registry copy lagged the repo: #1187 corrected a preset comment that stated the archived-project bug as a feature, and #1193 followed with no bump of its own. The bundle is already in sync (client schema + `client_version` at 3.23.0); this is the version bump that ships it. No code change — delivery only.
v1.24.02026-08-31
**The claim gate is the board's to declare, not the worker's to opt into.** `claimNextTask` used to consult a column's `claimable_by_roles` only when the caller passed a `role`. A caller that passed none — the default for a worker that has not been given one — took the scan-every-column branch instead, so a board could declare a staging column and still have cards claimed out of it. The board's declaration now decides. If any column on the board declares `claimable_by_roles`, a role-less claim is held to that declared set; a board that declares none anywhere keeps the scan-everything behaviour, so no board without claim lanes changes. An explicit `columns=[...]` still overrides, because naming a staging column is a deliberate act by a caller that knows the board. This is a **behaviour change** for boards that declare claim lanes, and the skill's prose was wrong about it in four places. Corrected here: the `claimNextTask` description and its `role` parameter in `schema.yaml`, plus the `set-up-claim-lanes` and `parallelize-a-plan-with-deps` recipes. One of the four was wrong as *advice* rather than description — the guidance told an agent whose claim was returning nothing to clear its role and scan every column, which after this change is a dead end, and which was offered precisely to the caller most likely to follow it. Skill version `3.22.0` → `3.23.0`. No method, parameter, or route changed — this release is prose only, and it exists because the code shipped in the platform without it. The published `1.23.0` bundle still describes the *old* rule; a brand on `latest` gets the correction on the next auto-update pass.
v1.23.02026-08-31
**An archived project is not an active one.** Corrects the rule stated in `1.22.0`. A board's project was resolved by counting projects that were non-deleted and same-tenant, with `is_archived` deliberately not a filter — so a board belonging to one active project and one archived project resolved as ambiguous and inherited nothing. Archiving a project silently voided a *different, live* project's standing rules on every board they shared, and the dashboard reported success. Archived projects are now excluded from that resolution, so `[1 active + 1 archived]` resolves to the active one. `references/project-bundles.md` and the `schema.yaml` bundle description are updated to state the new rule; the `1.22.0` note that `is_archived` is not a filter no longer holds. Skill version `3.21.0` → `3.22.0`. Published 2026-08-31.
v1.22.02026-08-30
**Agents can read and write a project's bundle.**
Two new methods, `getProjectBundle` and `setProjectBundle`, wrap the dedicated
sub-resource at `/board-groups/projects/{group_id}/bundle` — the commands,
skills, and rules that every card on a project's boards inherits at claim time.
The endpoint shipped in B.1a/B.2 and was reachable only from the dashboard until
now. Skill version `3.20.0` → `3.21.0`; tool count 79 → 81.
`setProjectBundle` **replaces** each field you send. It does not append. Send
`skills=["agentdocs"]` to a project that already has `["agentboard"]` and
`agentboard` is gone from every future build there — with a `200` and exactly
the bundle you asked for, which is what makes this the mistake that survives
review. Read with `getProjectBundle` first, extend, send the whole list. Omit a
field to leave it untouched; send `[]` to clear it.
The new `references/project-bundles.md` recipe gates on precisely that, tables
the three artifacts against their delivery lanes and caps (`commands`/`skills`
are names installed to the desk; `rules` are text inlined verbatim into every
brief and charged to every build), and maps each `project_bundle_skipped` value
— `none`, `ambiguous`, `empty`, `unresolved` — to its fix.
One correction worth stating plainly: the bundle reaches a card only when its
board belongs to exactly ONE project, counted as **non-deleted and same-tenant**.
`status` and `is_archived` are deliberately not filters, so a board in one
active and one archived project inherits nothing. The guidance says that rather
than the plausible-but-wrong "one active project".
Nothing here is delivered to a brand until this package is republished and the
brand upgrades.v1.21.02026-08-30
**The four build pins this package never received, plus the two new ones.** `createTask` and `updateTask` now accept the full per-card build bundle: `model`, `provider`, `harness`, `workflow_docs` (shipped to the repo in #1101 and never mirrored here) and `workflow_skills` + `workflow_rules` (new, migration 053). Until now an agent installing this package could not set a build pin at all — the API accepted every one of them and the schema offered none. The cause is the two-tree split. `apps/spideragent/packages/shared/skills/ agentboard/client/schema.yaml` is the authoring and drift-gate source; this file is the publish source, and the house convention is that they stay byte-identical. #1101 edited only the first. Both went on declaring skill version `3.19.0` over 54 lines of different content, which is what made them look reconciled — a package version is the only handle a brand has on package contents, and here even that agreed while the contents did not. `packages/opvs-skills/tests/agentboard-schema-trees.test.ts` now pins the two trees equal, so this cannot recur silently. Its sibling has pinned `SKILL.md` the same way since OSI-24; nothing had applied that to `schema.yaml`. Skill version `3.19.0` → `3.20.0`. No new methods — six added parameters on two existing ones, so the tool count is unchanged. Note: `1.20.0` was published without an entry in this file. Not backfilled here, because its contents are not this card's to describe.
v1.19.02026-08-15
**Tier 2 learns the short-ref grammar that Tier 3 already had.** `SKILL.md` gains the "Naming a board or a task" section, so an agent reading the guide — not just one reading a parameter description — knows a board key, a task ref and a UUID prefix are all accepted. This release exists because 1.18.0 shipped the grammar into the *schema* and the merged repo carried it into `SKILL.md`, but the published 1.18.0 bundle predates that `SKILL.md` edit. The source change merged without a version bump, so repo 1.18.0 and registry 1.18.0 held different content. A package version is the only handle a brand has on package contents, so the correction is a new version — never a republish in place. ### Added - **`SKILL.md` — "Naming a board or a task (`board_id`, `task_id`)".** The four accepted forms in a table, the promise that full UUIDs are never deprecated, and the two rules that actually bite: **case is the disambiguation** (`ops` is not `OPS` — a lowercased key matches no shape and 404s, it does not fall back), and an ambiguous prefix returns **409 `ambiguous_ref`** listing candidates rather than guessing. Notes that a few routes are UUID-only and that the per-route parameter text is the narrower truth when the two disagree. ### Unchanged - No method added, removed or renamed. Tool count still 79. `schema.yaml`, all 21 `references/`, all 40 `learnings/` and every script are byte-identical to 1.18.0 — a full recursive diff of the published 1.18.0 bundle against this tree reports exactly one differing file, `skills/agentboard/SKILL.md` (+30 lines, additive). - No change to `entitlements.required`, so the auto-update poller has no entitlement drift to hold on and every active pin (`^1.0.1`, `^1.1.0`, `^1.2.0`, `latest`) is satisfied.
v1.18.02026-08-15
**`board_id` and `task_id` now document the short-reference forms.** Guidance-only: no method added, removed or renamed, no parameter type changed. Tool count unchanged (79), so the generator's hardcoded assertion did not move. ### Changed - **57 parameter descriptions** across both schema trees. Boards accept a key (`OPS`), tasks accept a ref (`OPS-142`), and either accepts a UUID prefix of 8+ hex characters or a full UUID. Full UUIDs are not deprecated and never will be. - **The grammar is stated once** in the top-level `guidance.pitfalls`, including the part that actually bites: case is the whole disambiguation. Board keys are UPPERCASE, UUID prefixes are lowercase hex, so `ops` is not `OPS`. An ambiguous prefix returns **409** with the candidates listed instead of guessing one. ### Not uniform — five parameters say the opposite, on purpose Coverage was computed per-parameter against the gateway's real allowlists (`PATH_RULES` + `BODY_REF_KINDS` in `services/ref_canonicalization.py`), not assumed. **52 slots are ref-capable; 5 are not**, and those five carry *"Full UUID only — this route does not resolve short refs"*: | Method | Param | Why it cannot resolve | |---|---|---| | `getBoardSummary` | `board_id` | query parameter, and a GET has no body to walk | | `getTaskDistribution` | `board_id` | same | | `searchTasks` | `board_id` | same | | `removeBoardFromProject` | `board_id` | `/board-groups/…` matches no path rule | | `sendEmailFromCard` | `task_id` | the two-identifier rule needs a literal `/tasks/` segment | A blanket "accepts a ref" would have been a false promise on all five. Twelve methods share the literal description text `"Board UUID"` and one of them — `getBoardSummary` — is in that table, so the edit had to key on the method, not on the text. ### Note on 1.17.0 **1.17.0 was bumped in git but never published to the registry.** PR #1003 moved `package.yaml` to 1.17.0 and added no changelog entry, leaving the newest published version at 1.16.0. Its `sendEmailFromCard` send-status guidance therefore ships to brands for the first time here, in 1.18.0. 1.17.0 is skipped rather than reused, so each version number keeps naming exactly one content snapshot.
v1.16.02026-08-12
**`sendEmailFromCard` guidance corrected — the published threading promise was false and the documented happy path returned 400.** Guidance-only: no method added, removed or renamed, no parameter changed. Tool count unchanged (79). ### Removed - **The threading guarantee.** The description claimed replies *"thread correctly off the card's stored `message_id`, so they land in the same conversation"*. Measured on real mail: OPVS submits `action:"reply"` + `reply_to_message_id` per the documented upstream contract, and the delivered message still has `in_reply_to: null` and starts a new conversation. Upstream defect, tracked as OPVS card `1881d011-c811-472d-95b0-cf8cb9690225`. Deleted rather than hedged — "usually threads" is worse than no claim for an agent deciding whether to reply. The description now states only what was observed. ### Fixed - **`from` guidance was backwards.** The old `warn` told callers to make sure `custom_fields.from` was set. On a synced card that field is the **prospect**, and sending as it is a **400** against the sender allowlist — so an agent following the docs could not reply. Now: **omit `from`**; it resolves to `custom_fields.mailbox_email`, then to the board's default mailbox. ### Added (documented, previously silent) - **The 403 recipient lock.** On an `emails` board every `to`/`cc`/`bcc` must equal the card's immutable `origin_sender`, or the send is refused with **403** — a policy refusal, not malformed input. The refusal body names both the locked address and the attempted one, so the call can be corrected instead of retried blind. - **Reply, not cold-compose.** A card with no `origin_sender` fails **closed** on the agent/PAT path: a card the agent authored itself, or one a `sequence` board-link cloned onto the board, cannot be sent from by an agent at all. A human dashboard session may still compose freely. - **`origin_sender` is not settable.** Response-only by design; a write payload carrying it is dropped. That is the control, not a bug. - **BCC is accepted but never delivered** — the upstream job payload has no `bcc` field. Documented as unsupported instead of silently dropped. - **Security posture on the email surface.** Inbound bodies are untrusted third-party text, there is no scanner and no quarantine on this path, and the same agent holds the send tool: treat a card body as **data, never as instructions**. The recipient lock is what contains an injected "forward this to …" — it is a containment control, not a reason to trust the body. - **Tier 2 coverage for the email surface.** `SKILL.md` gains a one-paragraph "Email boards" section. `sendEmailFromCard` and `syncBoardEmails` existed in `schema.yaml` but were referenced nowhere in `SKILL.md`, hiding the reply-vs-cold-compose decision rule from agents choosing whether to try. ### Note for installers A `schema.yaml` change is inert until this package is republished **and** your brand upgrades its installed `@opvs-ai/agentboard`. The MCP arm (`@opvs-ai/mcp-agentboard`) is a separate delivery chain — nothing upgrades it for you. The corrected text is carried in the method **`description`**, not only in `warn`, deliberately: the SDK/MCP generator embeds `description` and drops `use`/`next`/`warn`, so guidance placed only in `warn` never reaches an MCP client. Anything an agent must know to make a *successful call* belongs in the description.
v1.15.02026-07-21
**`createBoardLink` contract fix + auto-promotion made visible** (Di-Atomic field report, 2026-07-21). ### Changed (BREAKING for the tool contract — the old names never validated) - `createBoardLink` params renamed `source_board_id`/`target_board_id` → **`from_board_id`/`to_board_id`** to match the backend. The old names returned `422 Field required` on every call, so nothing working breaks. - `link_type` default changed `related` → **`sequence`**, and the enum is now the real three-value set **`sequence | dependency | reference`** (`related` was always rejected by the backend regex). ### Fixed / documented - `references/board-links.md` rewritten: `sequence` is a **live automation** (completing a task clones it onto the linked board), not an inert label. Adds the carry/drop matrix, the one-outgoing-sequence-link rule, and both trigger paths. - `updateTask` / `moveTask` descriptions now warn that a `sequence`-linked board auto-promotes on done.
v1.14.02026-07-20
Schema **3.14.0 — 79 tools** (was 3.13.0 / 77). Two methods added for the
"one card = shared state" launch model, both fixing a dead end an agent could
not work around.
### Added
- **`activateStage`** (`POST /tasks/{task_id}/stages/{stage_id}/activate`) — force a
stage to be the active one. Reopening a resolved card now re-arms the earliest
*pending* stage server-side automatically, so this is for the case where **every**
stage is already done and there is nothing pending to infer — or when you want to
jump back and redo a specific earlier stage. Demotes the current active stage to
pending, clears the target's completion, and returns a finished card to
`in_progress`.
- **`deleteFile`** (`DELETE /files/{file_id}`) — detach an attachment from a card.
The route existed but was suppressed as admin-only, so a superseded asset (e.g. a
re-rendered image) stayed on the card forever; `setCover` only repoints the cover.
Clearing the cover attachment now also clears the card's cover pointer.
### Fixed (server-side, no schema change)
- A **reopened card could not complete any stage** — `completeStage` 400'd on every
stage because reopening never restored an active stage. Fixed in the AgentBoard
service; no client change needed.
- An explicit stage `position` no longer collides with its siblings — inserts reflow
the rest instead of duplicating a position.v1.12.02026-07-18
Wave 2 of the Di-Atomic AgentBoard requests. Republish so the S2 stage-lifecycle
`artifacts` capability (merged into the schema earlier) becomes **visible to
MCP/agents** (a schema change is inert until the marketplace package is
republished).
### Added
- **`completeStage` `artifacts`** (S2, #3) — the stage-handoff call
(`completeStage`) now accepts an optional `artifacts` array of structured
deliverables. Each object is `{role (required), url, dims, prompt, …}` — extra
keys are preserved. Artifacts are deep-merged into the parent card's
`custom_fields.artifacts` keyed by `role`, so successive stages accumulate
outputs (re-emitting a role replaces it), and are also recorded on the stage's
handoff report. Use instead of a separate `updateTask` call when a stage
produces deliverables to pass to later stages.v1.11.02026-07-18
Wave 1 of the Di-Atomic AgentBoard requests. Three agent-surface capabilities that merged into the schema earlier become **visible to MCP/agents** with this republish (a schema change is inert until the marketplace package is republished). ### Added - **`attachFileFromUrl`** (S5) — attach a file to a card by public http(s) URL. The server fetches the bytes itself and stores them as a card-native attachment, so the file survives even if the source URL later goes away. The fetch is SSRF-guarded (internal / loopback / cloud-metadata URLs rejected with 400) and capped at 50 MB. Pass `file_type='image'` for the cover-image crop; omit it to store the original bytes verbatim. - **Batch `custom_fields` + `source_task_id`** (S4) — `bulkCreateTasks` rows can now carry per-row `custom_fields` (make a content_calendar post publish-ready in one call) and a `source_task_id` fan-out that sets a `spawned` parent→row link in the same call — no follow-up `addLink`. - **`updateTask` `custom_fields` + `custom_fields_merge`** (S1) — `custom_fields` is now a bound `updateTask` param. Set `custom_fields_merge:true` to deep-merge (RFC 7386) the patch into the card's existing blob — nested objects recurse, a null value deletes that key, scalars/arrays replace — so a partial edit no longer clobbers sibling keys another writer set. Default `false` = full replace. ### Changed - **createTask / updateTask guidance** (S1, #9) — corrected the stale "keys outside the board type's schema are silently dropped" wording. `custom_fields` are stored **verbatim** — every key persists whether or not it is in the board type's schema, so a typo'd key is not dropped, it just sits on the card unused. `getTask` to confirm your keys landed.
v1.10.02026-07-12
### Added - **content_calendar agent surface** — `createTask` accepts `custom_fields` so a content_calendar card is publish-ready (Blotato) on create (#684); P.1 wired the full content_calendar agent surface across the skill + the CLI `--field` flag (#721).
v1.9.12026-07-01
board-doctor `star_topology` now counts **transitively-reduced (top-layer)** fanout, not raw direct edges. A keystone's real blast radius is the dependents that unblock the *instant* it lands; a dependent serialized behind another dependent (a chain `C→B→A→hub`) is deferred, not part of the herd. Serializing dependents is the canonical way to de-fang a keystone without splitting it, so a chain-reduced hub now **passes**. (Motivated by a live VayaCore board: hub with 8 direct dependents but only 5 top-layer after 3 serialized chains.) ### Changed - **`board-doctor.mjs` CHECK 10 `star_topology`** — computes top-layer fanout via transitive reduction (a direct dependent is dropped if it transitively depends on another direct dependent of the same hub); WARNs only when the reduced count exceeds the threshold, and reports both counts (`N cards depend … (M direct …)`). - Companion `skill_guidance.compute_dag_findings` star finding uses the same reduction (ships via api-gateway). `references/run-a-factory-board.md` §2.5 rule 2 now names both fixes (split OR serialize). 2 new doctor fixtures + 2 Python finding tests.
v1.9.02026-06-30
Board-doctor v2 — graph QUALITY checks for the "wired-but-wrong" factory board.
1.8.0's `flat_graph` proves the DAG *exists*; a real client board (VayaCore)
passed every v1 check (binding · drift · acyclic · flat_graph · no_claimable_column)
and was still un-runnable-as-intended. These checks catch *why*.
### Added
- **`board-doctor.mjs` checks 7–10** (factory-only; extracted as the pure,
unit-testable `graphQualityChecks()`):
- **`missing_task_type`** (**FAIL**) — a non-done factory card with no
`task_type` routes to the default model and the run ledger can't key on type
(a silent capability loss invisible from the board).
- **`dead_dependency`** (**WARN**) — a `depends_on` whose prerequisite is parked
(`status=blocked`, not in a done column) can never reach done → the dependent
is a permanently un-runnable zombie.
- **`epic_as_task`** (**WARN**) — an `epic`-labeled / `EPIC:`-titled card in a
claimable column; a worker claims a container with nothing concrete to build.
- **`star_topology`** (**WARN**) — one prerequisite that >5 cards depend on: a
bottleneck hub with no layering (thundering herd / single point of stall).
- **`references/run-a-factory-board.md` §2.5 "Shape the graph WELL"** — the seven
authoring rules behind checks 7–10 (task_type, waves-not-star, one true start,
no epics-as-cards, no dead deps, intent-as-structure, board≠changelog) + the
full pre-arm gate.
- **`learnings/2026-06-30-factory-board-wired-but-wrong/`** — the VayaCore case,
the sequel to the flat-graph Trello trap.
- **`scripts/__tests__/board-doctor.graph-quality.test.mjs`** — 13 `node --test`
fixtures (board-doctor is now importable; `main()` guards on `process.argv[1]`).
### Changed
- `board-doctor.mjs` header + §6/Verify in the recipe now list checks 7–10.
- Companion envelope changes ship in the main API (`skill_guidance.py`):
`compute_create_task_guidance` nudges `missing_task_type` + `research_label_no_dep`
at create time; `compute_dag_findings` adds a `star_topology` finding alongside
`flat_graph`. `dead_dependency` stays doctor-only (needs full column data).v1.8.02026-06-30
Run-a-factory-board guidance — kill the two silent traps that let a `board_type="factory"` board look fully set up yet build nothing. Skill-side half of the GS.0 factory-board guidance audit (the envelope `_guidance` half ships separately). ### Added - **`references/run-a-factory-board.md`** — new keystone recipe for operating a factory board start to finish: what a factory board is/isn't (inert until an opvs-sidecar worker is pointed at its `board_id`), the stock Backlog→Ready→Executing→Review→Done pipeline, the **Backlog→Ready** step (Trap 1: new cards land in non-claimable Backlog), the **worker role match** (Trap 2: Ready is claimable by `builder` — a mismatched role claims nothing), the **autonomy modes** (`auto`/`assisted`/`manual` + per-card `mode:<x>` label), the claim loop, lifecycle, and track/close. - **`board-doctor.mjs` check #6 — `no_claimable_column`** — for `factory` boards: **FAIL** when no column declares `claimable_by_roles` (the #450 silent no-op — the claim engine has no source); **WARN** when a claimable column exists but every pending card sits in a non-claimable column (the Backlog trap). Cheap check (board type + columns + the already-fetched task list). ### Changed - **`references/run-a-project-end-to-end.md`** — fixed the flagship claim example `role="backend"` → `role="builder"` (the stock factory role; `backend` claims nothing on a stock factory board), and added the Backlog→Ready step + a pointer to the new factory recipe. - **`references/set-up-claim-lanes.md`** — role examples → `builder`; added a note that the stock factory claimable role is `builder` + cross-link to the recipe. - **`SKILL.md`** — new routing row for the factory recipe; clarified `factory` board TYPE (claim engine) vs the `factory-stages` PRESET (a plain `tasks` board, no claim engine); board-doctor scripts-table now lists check #6. - **`SKILL.md` frontmatter** `version` 3.9.0 → 3.10.0 and `client_version` 3.7.0 → 3.10.0 — corrected to match `schema.yaml` (3.10.0), which #523's release left stale. Package 1.7.0 → 1.8.0; schema methods unchanged.
v1.7.02026-06-30
Email Board methods — agents can now operate AgentBoard Email Boards
(`board_type='emails'`) end-to-end via Path-B `skill_call`. Sessions A
(audit) + B (#522 — auto-sync loop, reply threading, metadata fixes)
landed the backend; this exposes the two email endpoints as typed
skill methods so a hire on a shared Email Board can sync mail and
reply from a card.
### Added
- **`syncBoardEmails`** — wraps `POST /api/v1/board/boards/{board_id}/email/sync`.
Pulls new mail from the board's mapped SpiderMail mailbox(es) into
cards on demand (each message → a card with the full body in
`description` + threading metadata in `custom_fields`). Complements
B's background auto-sync loop.
- **`sendEmailFromCard`** — wraps `POST /api/v1/board/boards/{board_id}/email/send/{task_id}`.
Sends/replies FROM a card; the card's `title`/`description`/
`custom_fields.from|to|cc|bcc` ARE the email, and replies thread off
the stored `message_id` (#522). Guidance steers the agent to
`updateTask` the body + recipients BEFORE sending.
- Both methods carry OPVS-native `guidance` blocks (use / next / warn)
and a new `# ── Email Boards ──` section documenting the card-IS-the-
email model and pointing raw-mailbox needs at the dedicated email
skill (no read-method duplication).
### Changed
- Skill `version` 3.9.0 → 3.10.0 (schema.yaml); package 1.6.0 → 1.7.0.
### Notes
- **No read methods mirrored.** A card already carries the full email
body (`description`) + thread metadata (`custom_fields`); `getTask`
reads it. Email-board hires that need raw inbox/thread/compose-assist
should ALSO install the dedicated email skill
(`send-receive-email` / SpiderMail) rather than duplicating it here.v1.6.02026-06-28
Best-in-class rebuild — teach the project METHOD, not just the endpoints. #463
proved agents had the DAG capability and recipe yet built flat Trello boards;
this ships the spine + recipes + enforcement that close the adoption gap.
### Added
- **Project-method spine** in `SKILL.md`: the `PLAN → SHAPE → WIRE → RUN →
TRACK → CLOSE` workflow, each phase routing to a recipe. The board is "a plan
the claim engine can run", not a to-do list.
- **`board-doctor` CHECK 5 — `flat_graph`**: a factory board with ≥2 tasks and 0
dependency edges is now a `✗ FAIL` the agent must paste (INFO/PASS on plain
`tasks` boards, where a flat board is legitimate). The Trello trap is now a
fact the agent can't fudge, not a sentence.
- **7 new recipes**: `run-a-project-end-to-end` (keystone), `pick-a-board-preset`,
`set-up-claim-lanes`, `planner-inbox-and-master-views`, `marker-workflows`,
`board-links`, `bulk-update-tasks`.
- **Learning KI** `2026-06-28-factory-board-flat-graph-trello-trap` — the #463
root cause + the 4-lever fix + the shared `flat_graph` label contract.
### Changed
- `parallelize-a-plan-with-deps` now leads with the **one-shot bulk DAG**
(`agentBatchCreateTasks` `ref`/`depends_on_refs`) instead of create-then-link;
Verify section gains the `board-doctor` flat_graph gate.
- `SKILL.md` description enriched with new phrasings ("run a whole project",
"set up claim lanes", "pick a board preset", "see my work across boards",
"tag tasks with markers", "link two boards", "bulk-update tasks"); skill
version 3.8.0 → 3.9.0.v1.5.02026-06-28
DAG adoption — steer agents to build dependency graphs, not flat Trello boards. ### Changed - **createTask guidance** now nudges dependencies: `next` tells the agent to set `depends_on` / `addDependency` and (on a factory/DAG board) work the `getRunnable → claimTask` loop instead of just `moveTask`; `warn` flags that flat tasks never enter the runnable/claim engine, and points at `references/parallelize-a-plan-with-deps.md`. `createTask.description` documents inline `depends_on`. `schema.yaml version → 3.9.0`. - **createBoard guidance** explains `board_type:factory` is a dependency graph — link tasks after adding them. ### Added - **One-shot DAG via `agentBatchCreateTasks`.** Bulk items gain `ref` (temp id), `depends_on` (existing task ids), and `depends_on_refs` (refs of other items in the same batch). A second pass resolves refs → real ids and writes the `blocked_by` links, so an agent can lay down a whole dependency graph in a single call instead of create-then-link-separately (the friction that made agents skip dependencies).
v1.4.02026-06-27
Factory board-type surface propagation. The dashboard shipped a "factory"
board type (agent-ops kanban + DAG view + tasks↔factory switch) and the
`GET /boards/{id}/dag` endpoint, but the published skill package lagged Tree A,
so agents could neither create a factory board, switch a board's type, nor read
the dependency graph. This republish closes that gap. `schema.yaml version →
3.8.0`. Additive — no breaking changes.
### Added
- **`getBoardDag` method.** `GET /boards/{board_id}/dag` — the whole-board
dependency graph (every `blocked_by` edge + per-task runnability map) in one
call. Powers the dashboard DAG view; previously bound in Tree A (#437) but
never published.
- **`factory` board type on `createBoard`.** `board_type` enum gains `factory`
(Backlog→Ready→Executing→Review→Done preset), so agents can provision an
agent-ops board, not just the dashboard.
- **`board_type` param on `updateBoard`.** Exposes the tasks↔factory switch
(any other value → 400). Lets a Planner convert an existing board in place.
The AgentBoard-upgrade consolidation republish (Topic 3 S3.3, the FINAL slice).
Assembles the canonical authoring tree
(`apps/spideragent/packages/shared/skills/agentboard/`, Tree A) into this
publish package (Tree B) and ships it signed so Path-B agents finally get the
full new surface. Covers the deferred S1.6 + S2.4 content below, plus the
Topic-6 DAG methods and the S3.1 standard/harness.
### Added
- **Task-DAG methods + `mutex_group` bound (Topic 6 / S6.1 + S6.3).**
`listDependencies`, `addDependency`, `removeDependency`, `getRunnable`, and
`claimTask` are now bound skill tools, and `createTask`/`updateTask` gain the
optional `mutex_group` lane param (≤1 `in_progress` per `(board, mutex_group)`
— the safe-claim backstop). `skills/agentboard/schema.yaml` `version → 3.7.0`.
These shipped to Tree A as Topic 6 landed but had not yet been published.
- **S3.1 standard + run-and-paste harness shipped in the package.** The
`scripts/` dir is now part of the bundle: `board-doctor.mjs` (live-board
invariant checker — column→status binding, drifted status, DAG acyclicity,
mutex lanes), `plan-render.mjs` (deterministic board → plan/PRD Markdown),
`check-skill-shape.sh` (4-layer shape doctor), and `verify-board-shape.mjs`.
`AUTHORING.md` (the authoring standard) ships alongside. `SKILL.md` is the
dense S3.1 router rewrite (`version → 3.8.0`): ~15 user phrasings, a single
sharpened `<HARD-GATE>` on the `updateTask(status="done")` reflex, sibling
routing, and a "Scripts — run, then paste verbatim" workflow section.
- **42 `learnings/` KIs + 12 `references/` recipes** carried from Tree A (the
S3.2 content pass): the full port of `docs/planning/AgentBoard/LEARNINGS.md`
plus the goal-open recipes (`set-up-a-crm-workspace`, `file-and-track-a-ticket`,
`parallelize-a-plan-with-deps`, `column-status-binding`, `read-board-as-a-plan`,
`projects`, …) and 6 schema-validated `registry/` board templates.
- **9 Projects methods + `references/projects.md` (S2.4 / Topic 2).** `listProjects`, `getProject`, `createProject`, `updateProject`, `setProjectStatus`, `archiveProject`, `addBoardToProject`, `removeBoardFromProject`, `getProjectTasks` are now bound skill tools on `skills/agentboard/schema.yaml` (`schema version → 3.6.0`) — promoted from drift-ignored dashboard routes so agents reach Projects via `skill_call`. A Project is a `BoardGroup(kind="project")`: a many-to-many container above boards with its own lifecycle (`status` active/on_hold/completed ⟂ `is_archived`) and a closing handoff. New `references/projects.md` teaches the mental model, the manual-status `<HARD-GATE>`, and the remove-board≠delete-board anti-pattern; router-table row + anti-pattern added to `skills/agentboard/SKILL.md`. `createProject`/`updateProject` narrow `settings`/`brand_id` (proxy-injected) via the drift allowlist. _(Published in this 1.3.0 republish; the final schema is 3.7.0 after Topic-6 DAG landed on top.)_
- **`read-board-as-a-plan` reference + `exportBoardMarkdown` detail/columns params (S1.6 / Topic 1).** New `references/read-board-as-a-plan.md` teaches reading a whole board (or a column subset) as one plan/PRD Markdown document, with a router-table row in `skills/agentboard/SKILL.md`. The `exportBoardMarkdown` tool in `skills/agentboard/schema.yaml` gains `detail` (enum `summary`/`standard`/`full`, default `standard`) and `columns` (comma-separated names-or-ids) params, matching the live AgentBoard `GET /boards/{id}/export?format=md` endpoint shipped in S1.1. _(Published in this 1.3.0 republish.)_v1.2.02026-06-01
### Added - **`updateTask` can now edit the agent-execution fields.** `agent_instructions`, `agent_context`, `labels`, `due_date`, `assigned_to_agent_id`, `parent_task_id`, and `depends_on` are now exposed as optional partial-update params on `updateTask`. Previously only `title`/`status`/`priority`/`agent_result`/`description`/`column_id` were editable, so a task's `agent_instructions` brief was effectively immutable after creation — Planners had to layer "CANONICAL BRIEF supersedes…" correction comments. The backend `TaskUpdate` schema already accepted all of these; this only surfaces them through the tool schema. Reassignment uses the real `assigned_to_agent_id` field (not the unmapped `assignee_id` alias). Drift allowlist updated so these stay at 0 drift.
v1.1.12026-05-29
### Fixed - **`cancelled` task status now in the manifest (#135).** `updateTask`, `listTasks`, and `viewBoardTasks` status enums gained `cancelled` (the only legal terminal transition out of `pending`, per the backend `VALID_STATUS_TRANSITIONS`). Previously omitted, so agents couldn't discover it via `tool_help`. `updateTask.status` description now spells out the transition rule (pending → assigned/in_progress/cancelled; not directly to done). No code change — schema/manifest discovery only. Published to the registry 2026-05-29 (id `ec682cd3`, signed `SHA256:f97b15…`, score 100, tier=beta).
v1.1.02026-05-25
### Added - **Initiative A — envelope contract (sei.1.1 / PR #76).** schema.yaml is now version 3.4.0 with skill-level `intent_aliases`, `pitfalls`, and per-method `guidance` blocks carrying `next`, `warn`, and `telemetry_signal_default`. Lets the gateway surface OPVS-native guidance inline in every tool description and ride forward chains across calls. - **Initiative B — 4-layer format (s4l.1.1 / PR #84).** Three new directories ship inside `skills/agentboard/`: `references/` (6 procedure docs — create-task, bulk-create-tasks, comment-threading, find-before-creating, move-task-between-columns, multi-stage-handoff), `learnings/` (5 Knowledge Items, 2026-04-22 + 2026-05-22 entries), and `registry/` (5 typed assets — bug-fix-pool, company-enrichment, factory-stages, planner-orchestration-v2, sales-pipeline-deals, plus the registry.json index). - Republish on the canonical 4-layer recipe verified 2026-05-25 (see `docs/planning/Marketplace/DEPLOYMENT.md` §"4-layer skill publish"). 4-layer dirs ride along in the signed tarball; no manifest schema changes required. ### Changed - Skill SKILL.md regrown from ~92 lines to ~200 lines to carry the new envelope guidance and 4-layer pointers.
v1.0.32026-04-24
### Added
- **Marketing metadata** — `marketing` block now carries a `long_description` (2–4 paragraphs of admin-facing copy), 5–7 `features` bullets with lucide-react icons, and an `author` record ({name: OPVS Team, email: ops@opvs.ai, website: https://opvs.ai}). Drives the Wave 2 Phase B customer detail page at `/dashboard/marketplace/packages/@opvs-ai/<name>`. `media` block intentionally empty for this release — visual assets (hero image, screenshots, demo video) come in a later wave.v1.0.22026-04-24
### Changed - `tier: internal` → `tier: beta`. The dashboard customer browse at `/dashboard/marketplace` strips tier=internal by design (per marketplace concept: "internal = no public catalog entry"). Wave 1 is customer-facing — brand admins install `@opvs-ai/platform-skills` to get the OPVS platform. `beta` is the right tier per concept: "published + opted-in per brand, pre-1.0." - Peer_dependency ranges still `^1.0.0` — matches 1.0.0, 1.0.1, AND 1.0.2 via npm-style.
v1.0.12026-04-24
### Changed - Republished with `meta_coherence` fix (server-side 979b3b41) — score now 100/100. The 1.0.0 publish scored 95 due to a false-positive `meta.mixed_semantics` warning that penalised every package declaring `@opvs-ai/opvs-foundation` as a peer_dep. The warning has been removed; the BLOCKING `meta.empty_useless` guardrail stays.
v1.0.02026-04-23
### Added - Initial marketplace release. Packages the in-tree `agentboard@3.1.0` skill verbatim — ~70 methods covering tasks, boards, columns, stages, markers, files, comments, activity, velocity, and cost metrics. - Peer dependency on `@opvs-ai/opvs-foundation@^1.0.0`.













































