From 0452b6c05fff853efe0906518fccbcaeaacc8619 Mon Sep 17 00:00:00 2001 From: Andrii Pasternak <44377756+AndriiPasternak31@users.noreply.github.com> Date: Tue, 6 Oct 2026 22:21:18 +0100 Subject: [PATCH 1/8] test(skills): the bundled-catalog pin floor is v0.3.0, and the user doc joins the parity check (#3123) --- tests/unit/test_2545_skill_source_pin.py | 91 ++++++++++++++++++------ 1 file changed, 71 insertions(+), 20 deletions(-) diff --git a/tests/unit/test_2545_skill_source_pin.py b/tests/unit/test_2545_skill_source_pin.py index 30452eb5a5..feefec9131 100644 --- a/tests/unit/test_2545_skill_source_pin.py +++ b/tests/unit/test_2545_skill_source_pin.py @@ -7,22 +7,27 @@ with the catalog's releases", and the library had been ahead of the pin since v0.1.1 by the time #2545 moved it. -Three properties, none of them a literal that the next bump must edit: - -* **Floor, not literal.** The pin is at least v0.2.0 — the release that added - the `project-management` category. A floor fails on a regression (a bad merge - or revert resetting the pin) and stays valid across every future bump; an - exact-literal assertion would just be a change-detector. +Four properties, none of them a literal that the next bump must edit: + +* **Floor, not literal.** The pin is at least v0.3.0 — the release that added + `update-dashboard`, the playbook the metrics tiles point users at (#3123; + #2545 had set the floor at v0.2.0, the `project-management` release). A floor + fails on a regression (a bad merge or revert resetting the pin) and stays + valid across every future bump; an exact-literal assertion would just be a + change-detector. * **Parity with the documented example.** `.env.example` shows the default as the value of `TRINITY_DEFAULT_SKILL_SOURCE_REF`. A stale example is exactly - the "docs mention of the default pin" line item the bump's AC carries; this - makes the next bump a two-file change that cannot leave one behind. + the "docs mention of the default pin" line item the bump's AC carries. +* **Parity with the user doc** (#3123). `docs/user-docs/automation/ + skills-and-playbooks.md` states the current pin in prose; #2551 had to + remember it by hand. With both parity checks the next bump is a three-file + change that cannot leave one behind. * **The seed note reports the configured ref** (AC#1) — the one line an operator sees at boot that says which catalog their fresh install got. -Both static checks parse SOURCE, not the imported module: `config.py` honours -the env var, so a developer's shell override would otherwise leak into the -assertion. +All three static checks parse SOURCE, not the imported module: `config.py` +honours the env var, so a developer's shell override would otherwise leak into +the assertion. """ from __future__ import annotations @@ -36,11 +41,36 @@ _REPO = Path(__file__).resolve().parents[2] _CONFIG = _REPO / "src" / "backend" / "config.py" _ENV_EXAMPLE = _REPO / ".env.example" - -# The release that introduced the `project-management` category (14 runtime -# skills) — the reason #2545 moved the pin. Raise only when a later release -# becomes the new floor an install cannot do without. -_FLOOR = (0, 2, 0) +_USER_DOC = _REPO / "docs" / "user-docs" / "automation" / "skills-and-playbooks.md" + +# The three files that state the bundled pin; they move together. +_PIN_FILES = ( + "src/backend/config.py, .env.example and " + "docs/user-docs/automation/skills-and-playbooks.md" +) + +# Why v0.3.0 (#3123): it is the first catalog that lets an agent get, from the +# Library, the `update-dashboard` playbook that +# `metric_read_service.EMPTY_METRIC_MESSAGE` and the Dashboard tile +# (`DashboardPanel.vue`, "Run /update-dashboard playbook") name. That copy says +# "if the agent has that playbook", so the floor is about availability, not a +# broken promise. (v0.2.0, #2545's floor, added the `project-management` +# category.) Raise only when a later release becomes the new floor an install +# cannot do without. +# +# The limit: this guards the VERSION, not whether `update-dashboard` is in the +# tag. Before moving the pin, check membership against the real upstream tag — +# it must print the path: +# +# git clone --bare https://github.com/abilityai/trinity-skills /tmp/ts +# git -C /tmp/ts ls-tree --name-only -r skills/update-dashboard/SKILL.md +# +# And review what the new tag brings into a fleet (skills carry executables): +# +# git -C /tmp/ts diff --stat -- ':!*.md' # non-instruction files +# git -C /tmp/ts diff --name-status # added / modified files +# git -C /tmp/ts diff | grep -E '^\+.*https?://' # URLs in added lines +_FLOOR = (0, 3, 0) def _config_default_ref() -> str: @@ -58,24 +88,45 @@ def _env_example_ref() -> str: return m.group(1) +def _user_doc_refs() -> list[str]: + return re.findall(r"`(v\d+\.\d+\.\d+)` of `trinity-skills`", _USER_DOC.read_text()) + + def _semver(tag: str) -> tuple[int, ...]: m = re.fullmatch(r"v(\d+)\.(\d+)\.(\d+)", tag) assert m, f"bundled pin {tag!r} is not a vMAJOR.MINOR.PATCH tag (ent#237 AC#5: tag-pinned)" return tuple(int(x) for x in m.groups()) -def test_default_pin_is_at_least_the_project_management_release(): +def test_default_pin_is_at_least_the_floor_release(): ref = _config_default_ref() + floor = "v" + ".".join(map(str, _FLOOR)) assert _semver(ref) >= _FLOOR, ( - f"DEFAULT_SKILL_SOURCE_REF={ref!r} is below v{'.'.join(map(str, _FLOOR))}: a fresh " - "install would seed a catalog without the project-management skills (#2545)" + f"DEFAULT_SKILL_SOURCE_REF={ref!r} is below the floor {floor}. A fresh install " + "would seed a catalog without `update-dashboard`, the playbook " + "metric_read_service.EMPTY_METRIC_MESSAGE and the Dashboard tile send users to " + f"(#3123). Fix: move the pin in {_PIN_FILES} together, then re-run the " + "membership check in the _FLOOR comment against the new tag." ) def test_env_example_documents_the_same_default(): assert _env_example_ref() == _config_default_ref(), ( ".env.example's TRINITY_DEFAULT_SKILL_SOURCE_REF example is stale — the " - "pin is bumped in config.py AND .env.example together (#2545)" + f"pin is bumped in {_PIN_FILES} together (#2545, #3123)" + ) + + +def test_user_doc_states_the_same_default(): + refs = _user_doc_refs() + assert len(refs) == 1, ( + f"expected exactly one \"`vX.Y.Z` of `trinity-skills`\" in {_USER_DOC.name}, " + f"found {refs!r} — the pin sentence was reworded? update this regex" + ) + assert refs[0] == _config_default_ref(), ( + f"{_USER_DOC.name} states the bundled pin as {refs[0]!r} but config.py " + f"defaults to {_config_default_ref()!r} — the pin is bumped in {_PIN_FILES} " + "together (#3123)" ) From 1f9c1139634f2a4180d7459c93638206baf7ea65 Mon Sep 17 00:00:00 2001 From: Andrii Pasternak <44377756+AndriiPasternak31@users.noreply.github.com> Date: Tue, 6 Oct 2026 22:21:40 +0100 Subject: [PATCH 2/8] chore(skills): bump the bundled community-catalog pin to trinity-skills v0.3.0 (#3123) --- .env.example | 2 +- src/backend/config.py | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index e910bf8251..32ec0ffc42 100644 --- a/.env.example +++ b/.env.example @@ -335,7 +335,7 @@ SKILLS_FLEET_INJECT_CONCURRENCY=5 # agents re-injected in parallel during a flee # Pinned to a tag we bump, never a branch head — the catalog takes public PRs and # skills carry executables. Set the URL to "" to disable the seed entirely. # TRINITY_DEFAULT_SKILL_SOURCE=github.com/abilityai/trinity-skills -# TRINITY_DEFAULT_SKILL_SOURCE_REF=v0.2.0 +# TRINITY_DEFAULT_SKILL_SOURCE_REF=v0.3.0 # =========================================== # INSTALL PROVENANCE (#2380) diff --git a/src/backend/config.py b/src/backend/config.py index c83d5b0c4c..cdd6ae9d22 100644 --- a/src/backend/config.py +++ b/src/backend/config.py @@ -528,8 +528,10 @@ # quiet (a failed row in Settings), not loud. Bump this in lockstep with the # catalog's releases — the seed is fresh-install only, so a bump reaches new # installs and nothing else (#2545 moved it to v0.2.0, the release that added -# the project-management category; `.env.example` documents the same value and -# `tests/unit/test_2545_skill_source_pin.py` keeps the two in step). The env +# the project-management category; #3123 to v0.3.0, the release that added +# `update-dashboard`, which the metrics tiles point users at; `.env.example` and +# `docs/user-docs/automation/skills-and-playbooks.md` state the same value and +# `tests/unit/test_2545_skill_source_pin.py` keeps the three in step). The env # var is the escape hatch for an instance that wants an older or newer catalog. # # TRINITY_DEFAULT_SKILL_SOURCE="" disables the seed entirely for an operator who @@ -537,7 +539,7 @@ DEFAULT_SKILL_SOURCE_URL = os.getenv( "TRINITY_DEFAULT_SKILL_SOURCE", "github.com/abilityai/trinity-skills" ) -DEFAULT_SKILL_SOURCE_REF = os.getenv("TRINITY_DEFAULT_SKILL_SOURCE_REF", "v0.2.0") +DEFAULT_SKILL_SOURCE_REF = os.getenv("TRINITY_DEFAULT_SKILL_SOURCE_REF", "v0.3.0") DEFAULT_SKILL_SOURCE_NAME = "Trinity Community Skills" # ============================================================================ From 0252eb72012e5332f5c05c7489781a12516c5f29 Mon Sep 17 00:00:00 2001 From: Andrii Pasternak <44377756+AndriiPasternak31@users.noreply.github.com> Date: Tue, 6 Oct 2026 22:22:35 +0100 Subject: [PATCH 3/8] docs(skills): user doc + feature-flow row for the v0.3.0 pin (#3123) --- docs/memory/feature-flows/skills-library-sync.md | 5 +++-- docs/user-docs/automation/skills-and-playbooks.md | 14 +++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/memory/feature-flows/skills-library-sync.md b/docs/memory/feature-flows/skills-library-sync.md index 66ffa14c4e..3990deeaaa 100644 --- a/docs/memory/feature-flows/skills-library-sync.md +++ b/docs/memory/feature-flows/skills-library-sync.md @@ -707,6 +707,7 @@ CREATE TABLE IF NOT EXISTS system_settings ( | Date | Changes | |------|---------| +| 2026-10-06 | **#3123**: bundled community-catalog pin bumped to `trinity-skills` **v0.3.0** (fresh-install seed only). The catalog gains `update-dashboard`, the playbook the metrics tiles already point users at, and drops the four retired `add-*` installers (now marketplace-only), giving 38 skills. The guard floor rises to v0.3.0, and `docs/user-docs/automation/skills-and-playbooks.md` joins `.env.example` in the parity check. Existing instances keep their row (ent#529). | | 2026-09-30 | **ent#672**: the listing the sync produces now carries each skill's lifecycle keys — `deprecated` and `superseded_by` (the library's `superseded-by`) — parsed on every listing, never persisted, so a re-sync that drops the key clears the flag. Contract details: [skill-injection.md](skill-injection.md). | | 2026-09-06 | **#2545 + #2550**: bundled community-catalog pin bumped to `trinity-skills` **v0.2.0** (fresh-install seed only — adds the `project-management` category, 14 skills; `.env.example` documents the same value, `tests/unit/test_2545_skill_source_pin.py` keeps them in step). Update-path tag pin now compares the tag **peeled** (`refs/tags/^{commit}`): an annotated tag's bare rev-parse is the tag object, so the unmoved bundled source was refused as `moved_tag` on every sync after the first (`tests/unit/test_2550_annotated_tag_pin.py`, both tag kinds). | | 2026-07-29 | **ent#236 lifecycle automation**: scheduled leader-locked auto-sync, commit-gated fleet-wide re-inject with an honest per-agent report, durable sync status (`--workers 2` gap), and the dedicated range-validated `GET/PUT /api/settings/skills-library` route. Removal-on-unassign is documented in [skill-injection.md](skill-injection.md). | @@ -716,5 +717,5 @@ CREATE TABLE IF NOT EXISTS system_settings ( --- -**Last Updated**: 2026-09-30 -**Status**: Verified - Updated for ent#672 lifecycle keys on the listing +**Last Updated**: 2026-10-06 +**Status**: Verified - Updated for #3123 bundled catalog pin v0.3.0 diff --git a/docs/user-docs/automation/skills-and-playbooks.md b/docs/user-docs/automation/skills-and-playbooks.md index 0b78ad17fe..82ab46ca63 100644 --- a/docs/user-docs/automation/skills-and-playbooks.md +++ b/docs/user-docs/automation/skills-and-playbooks.md @@ -49,7 +49,19 @@ Existing repositories keep working with no configuration. The resolved root is r Skills carry executable `scripts/`, and library automation can push them to your whole fleet unattended. So: -- The bundled **community source is pinned to a tag**, not a branch head — currently `v0.2.0` of `trinity-skills`. New upstream commits do not reach your fleet until the tag is bumped and you sync. The pin is a fresh-install seed: an existing instance keeps the source row it already has. To move it to a newer tag, an admin updates the source's ref through `PUT /api/skills/sources/{id}` (the Settings panel adds, syncs, disables, and removes sources but does not edit a ref in place) or removes the source and adds it again with the new tag. `TRINITY_DEFAULT_SKILL_SOURCE_REF` in `.env` changes the tag a fresh install is seeded with; `TRINITY_DEFAULT_SKILL_SOURCE=""` disables the seed entirely. +- The bundled **community source is pinned to a tag**, not a branch head — currently `v0.3.0` of `trinity-skills`. New upstream commits do not reach your fleet until the tag is bumped and you sync. The pin is a fresh-install seed: an existing instance keeps the source row it already has. To move it to a newer tag, an admin updates the source's ref through `PUT /api/skills/sources/{id}` (the Settings panel adds, syncs, disables, and removes sources but does not edit a ref in place) — the steps are below. Removing the source and adding it again with the new tag is **not** equivalent: a source added through `POST /api/skills/sources` is always a custom source, so it loses the bundled badge and gets the custom-source priority, which can change which source wins when two sources ship a skill with the same name. `TRINITY_DEFAULT_SKILL_SOURCE_REF` in `.env` changes the tag a fresh install is seeded with; `TRINITY_DEFAULT_SKILL_SOURCE=""` disables the seed entirely. + + **Moving an existing instance to a newer catalog tag** (replace `` with the tag you are moving to): + + 1. **Before you move.** A newer tag can drop skills — for example, `v0.3.0` dropped the four `add-*` installers (`add-backlog`, `add-project-management`, `add-canon`, `add-orchestrator`). An agent still assigned a dropped skill keeps its old files, but every later delivery reports "Skill not found in library". Unassign those skills first, or install them from the abilities marketplace as `/agent-dev:`. + 2. **Find the bundled row.** With an admin token (`POST /api/token`; agent MCP keys are refused), call `GET /api/skills/sources` and find the entry in `sources` with `"is_default": true`. Note its `id`, and its current `ref` for rollback. + - No such row (an instance migrated from the legacy single-repository setting, or one where the bundled source was removed): add the catalog as a custom source pinned to the tag instead (Settings → **Track: Tag**). + - The row is disabled: enable it. + 3. **Change the ref.** `PUT /api/skills/sources/{id}` with `{"ref": ""}`. Changing the ref resets the source's sync status to `never`. + 4. **Sync the whole library.** Use **Sync all** in the Settings skill-sources panel or **Sync now** on the Library's Skills tab (both call `POST /api/skills/library/sync`), not the per-source **Sync** button. Only the full sync starts the fleet re-inject, and only when automatic re-inject is on; a per-source sync leaves running agents on their old files. If scheduled auto-sync is enabled, it also picks up the change on its next run and may re-inject across the fleet. + 5. **Check.** Confirm the skills you expect from the new tag are in the Library (for `v0.3.0`, `update-dashboard`). + + **Rollback:** the same `PUT` with the `ref` you noted, then sync the whole library again. Any agent assigned a skill that only the newer tag carries will then report it missing. - **Custom sources track a branch by default**, because you control who can write to them. Choose **Tag** under **Track** to pin one instead. - **A pinned tag that moves is refused**, not adopted. If a tag now resolves to a different commit than the last sync, the sync reports `moved_tag` and leaves your fleet alone. Moving to new content means pointing the source at a new tag name — an explicit admin action. Annotated and lightweight tags are both compared by the commit they point at, so a release tag that has not moved is never refused. From 8c4748e35c27e018e430ef2a60ef01be4bbfa501 Mon Sep 17 00:00:00 2001 From: Andrii Pasternak <44377756+AndriiPasternak31@users.noreply.github.com> Date: Tue, 6 Oct 2026 23:43:19 +0100 Subject: [PATCH 4/8] =?UTF-8?q?docs(skills):=20upgrade=20steps=20=E2=80=94?= =?UTF-8?q?=20unassign=20dropped=20skills=20first;=20a=20per-source=20Sync?= =?UTF-8?q?=20skips=20the=20fleet=20re-inject=20(#3123)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/user-docs/automation/skills-and-playbooks.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/user-docs/automation/skills-and-playbooks.md b/docs/user-docs/automation/skills-and-playbooks.md index 82ab46ca63..cd2929197d 100644 --- a/docs/user-docs/automation/skills-and-playbooks.md +++ b/docs/user-docs/automation/skills-and-playbooks.md @@ -53,12 +53,12 @@ Skills carry executable `scripts/`, and library automation can push them to your **Moving an existing instance to a newer catalog tag** (replace `` with the tag you are moving to): - 1. **Before you move.** A newer tag can drop skills — for example, `v0.3.0` dropped the four `add-*` installers (`add-backlog`, `add-project-management`, `add-canon`, `add-orchestrator`). An agent still assigned a dropped skill keeps its old files, but every later delivery reports "Skill not found in library". Unassign those skills first, or install them from the abilities marketplace as `/agent-dev:`. + 1. **Before you move.** A newer tag can drop skills — for example, `v0.3.0` dropped the four `add-*` installers (`add-backlog`, `add-project-management`, `add-canon`, `add-orchestrator`). An agent still assigned a dropped skill keeps its old files, but every later delivery reports "Skill not found in library". Unassign those skills first. An agent that still needs one can get it from the abilities marketplace as `/agent-dev:` — a marketplace plugin, outside the Library. 2. **Find the bundled row.** With an admin token (`POST /api/token`; agent MCP keys are refused), call `GET /api/skills/sources` and find the entry in `sources` with `"is_default": true`. Note its `id`, and its current `ref` for rollback. - No such row (an instance migrated from the legacy single-repository setting, or one where the bundled source was removed): add the catalog as a custom source pinned to the tag instead (Settings → **Track: Tag**). - The row is disabled: enable it. 3. **Change the ref.** `PUT /api/skills/sources/{id}` with `{"ref": ""}`. Changing the ref resets the source's sync status to `never`. - 4. **Sync the whole library.** Use **Sync all** in the Settings skill-sources panel or **Sync now** on the Library's Skills tab (both call `POST /api/skills/library/sync`), not the per-source **Sync** button. Only the full sync starts the fleet re-inject, and only when automatic re-inject is on; a per-source sync leaves running agents on their old files. If scheduled auto-sync is enabled, it also picks up the change on its next run and may re-inject across the fleet. + 4. **Sync the whole library.** Use **Sync all** in the Settings skill-sources panel or **Sync now** on the Library's Skills tab (both call `POST /api/skills/library/sync`), not the per-source **Sync** button. Only the full sync starts the fleet re-inject, and only when automatic re-inject is on; a per-source sync leaves running agents on their old files. If a per-source **Sync** has already run on the new tag, the full sync finds that source unchanged and starts no re-inject (unless another source also moved) — restart the affected agents, since an agent's skills are delivered again when it starts, or re-deliver one agent's skills with `POST /api/agents/{name}/skills/inject`. If scheduled auto-sync is enabled, it also picks up the change on its next run and may re-inject across the fleet. 5. **Check.** Confirm the skills you expect from the new tag are in the Library (for `v0.3.0`, `update-dashboard`). **Rollback:** the same `PUT` with the `ref` you noted, then sync the whole library again. Any agent assigned a skill that only the newer tag carries will then report it missing. From b3dbb86ea0e0cd62dd6a00fdc23e70e601c6c560 Mon Sep 17 00:00:00 2001 From: Andrii Pasternak <44377756+AndriiPasternak31@users.noreply.github.com> Date: Tue, 6 Oct 2026 23:43:24 +0100 Subject: [PATCH 5/8] test(skills): chain the _FLOOR membership-check commands (#3123) --- tests/unit/test_2545_skill_source_pin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_2545_skill_source_pin.py b/tests/unit/test_2545_skill_source_pin.py index feefec9131..a72ce185b7 100644 --- a/tests/unit/test_2545_skill_source_pin.py +++ b/tests/unit/test_2545_skill_source_pin.py @@ -62,8 +62,8 @@ # tag. Before moving the pin, check membership against the real upstream tag — # it must print the path: # -# git clone --bare https://github.com/abilityai/trinity-skills /tmp/ts -# git -C /tmp/ts ls-tree --name-only -r skills/update-dashboard/SKILL.md +# git clone --bare https://github.com/abilityai/trinity-skills /tmp/ts && \ +# git -C /tmp/ts ls-tree --name-only -r skills/update-dashboard/SKILL.md # # And review what the new tag brings into a fleet (skills carry executables): # From 5ea4aa03884a35f9c2c96dafef4054556b08c938 Mon Sep 17 00:00:00 2001 From: Andrii Pasternak <44377756+AndriiPasternak31@users.noreply.github.com> Date: Tue, 6 Oct 2026 23:44:40 +0100 Subject: [PATCH 6/8] test(skills): register the bundled-catalog pin guard in tests/registry.json (#3123) --- tests/registry.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/registry.json b/tests/registry.json index 9cb08547b9..20e86797cf 100644 --- a/tests/registry.json +++ b/tests/registry.json @@ -1,5 +1,19 @@ { "test_files": [ + { + "file": "unit/test_2545_skill_source_pin.py", + "feature": "#2545, #3123", + "added": "2026-09-06", + "updated": "2026-10-06", + "categories": [ + "backend", + "skills", + "config", + "docs", + "unit" + ], + "description": "Bundled community skills-catalog pin guard (static, parses SOURCE so a shell override cannot leak in): `config.DEFAULT_SKILL_SOURCE_REF` is a vX.Y.Z tag at or above the floor v0.3.0 (#3123: the first trinity-skills release with `update-dashboard`, the playbook the metrics tiles name; #2545 set v0.2.0); `.env.example` and `docs/user-docs/automation/skills-and-playbooks.md` state the same default (exactly one regex match in the doc); the fresh-install seed note reports the configured ref." + }, { "file": "unit/test_3246_platform_alert_surfaces.py", "feature": "#3246", From a0db2032d23f87790d1ff843d4e49818e2f97258 Mon Sep 17 00:00:00 2001 From: Andrii Pasternak <44377756+AndriiPasternak31@users.noreply.github.com> Date: Tue, 6 Oct 2026 23:45:35 +0100 Subject: [PATCH 7/8] docs(feature-flows): index row for #3123; the flow's history row names the new upgrade steps (#3123) --- docs/memory/feature-flows.md | 1 + docs/memory/feature-flows/skills-library-sync.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/memory/feature-flows.md b/docs/memory/feature-flows.md index d48e066efa..453a08cf21 100644 --- a/docs/memory/feature-flows.md +++ b/docs/memory/feature-flows.md @@ -23,6 +23,7 @@ | Date | ID | Change | Flow | |------|-----|--------|------| +| 2026-10-06 | #3123 | chore(skills): **fresh installs seed the bundled community skills catalog at `trinity-skills` v0.3.0** (was v0.2.0). The tag adds `update-dashboard`, the playbook the metrics tiles already name, and drops the four retired `add-*` installers (marketplace-only now): 38 skills. `config.DEFAULT_SKILL_SOURCE_REF`, `.env.example` and the user doc move together; `tests/unit/test_2545_skill_source_pin.py` raises its floor to v0.3.0 and adds the user doc to its parity checks. The user doc gains the steps for moving an existing instance's bundled row to a newer tag (existing installs keep their row; ent#529). No runtime code change: the seed and the annotated-tag peel (#2550) already handle the tag. | [skills-library-sync.md](feature-flows/skills-library-sync.md) | | 2026-10-05 | ent#752 | feat(gate): **a gated skill is refused inside the agent unless its run was approved for it** (Claude Code only). A PreToolUse hook on `Skill` and on `Agent`/`Task` skill preloads (`/opt/trinity/hooks/skill-gate.py`, its own managed-settings drop-in, exec form) asks `POST /api/skill-gate/check` with the agent's own key; the run is cleared by #751's approved-run record or a new `self_approved` record written where a self-approval lets a run through (no migration). No answer → a root-owned marker decides (gated agents fail closed, others keep working); never exit 1. A self-approved `/chat` turn runs in its own session; `/health` reports `skill_gate_hook` | [skill-gate.md](feature-flows/skill-gate.md) | | 2026-10-05 | ent#568 | feat(delegation): **every caller is taught that a receipt means the work is running — never re-send on silence**. One text (`DELEGATION_CONTRACT`, byte-identical in `platform_prompt_service.py` and `src/mcp-server/src/delegation_contract.ts`) is spliced into the platform prompt's §Agent Collaboration and published verbatim in the `chat_with_agent` and every `chat_with_` description; `fan_out` / `send_message` repeat its rule sentence. Every `chat_with_*` `execution_id` receipt carries "Do not re-send: read the outcome with `get_execution_result(…)`", and the backend's REST "poll GET" receipts are rewritten with liveness-neutral leads. Each carrying description stays under Claude Code's 2,048-char cap — `chat_with_agent` had been cut there since #2958 | [mcp-orchestration.md](feature-flows/mcp-orchestration.md), [system-wide-trinity-prompt.md](feature-flows/system-wide-trinity-prompt.md), [mcp-agent-exposure.md](feature-flows/mcp-agent-exposure.md) | | 2026-10-03 | #3185 | feat(a2a): **the outbound client speaks 402 — a priced remote is an outcome, not an outage**. `_read_capped` collapsed every HTTP ≥ 400 into `rpc_http_error` without reading the body, so a remote answering 402 was unreachable: the caller saw neither the price nor a way to attach a token. 402/403 on the RPC hop are now classified BEFORE the encoding and length guards (a gzipped or oversized "pay me" read as an outage), both rails are read (the HTTP 402's `payment-required` header or body, and an in-band `x402.payment.status` task — checked before `_parse_task` on send AND poll, or a priced `input-required` reaches the agent as a prompt it polls forever), and the route answers **402** with an allowlisted `detail.payment` = `{summary, x402, truncated}`, scrubbed against the token, its base64 forms and its decoded leaves. `payment_rejected` / `rpc_forbidden` stay 502 with `remote_status`, so 402 ("buy") is always distinguishable from 403 ("top up"). The endpoint credential carries a `credential_kind` (`api_key` default — every pre-#3185 record — or `payment_token`, inferred from the value when omitted with the SAME predicate the client sends on), an x402 v3 token is flagged `credential_single_use` rather than refused, and the MCP tools return `payment_required` + `payment` + `task_id` + `do_not_retry` with a description that names who can act. Trinity never buys, never retries a priced call, and never snapshots a 402 — a stored one would replay "pay me" after the operator paid | [a2a-outbound-call.md](feature-flows/a2a-outbound-call.md), [architecture/backend.md](architecture/backend.md), [architecture/mcp-server.md](architecture/mcp-server.md) | diff --git a/docs/memory/feature-flows/skills-library-sync.md b/docs/memory/feature-flows/skills-library-sync.md index 3990deeaaa..948261bbc1 100644 --- a/docs/memory/feature-flows/skills-library-sync.md +++ b/docs/memory/feature-flows/skills-library-sync.md @@ -707,7 +707,7 @@ CREATE TABLE IF NOT EXISTS system_settings ( | Date | Changes | |------|---------| -| 2026-10-06 | **#3123**: bundled community-catalog pin bumped to `trinity-skills` **v0.3.0** (fresh-install seed only). The catalog gains `update-dashboard`, the playbook the metrics tiles already point users at, and drops the four retired `add-*` installers (now marketplace-only), giving 38 skills. The guard floor rises to v0.3.0, and `docs/user-docs/automation/skills-and-playbooks.md` joins `.env.example` in the parity check. Existing instances keep their row (ent#529). | +| 2026-10-06 | **#3123**: bundled community-catalog pin bumped to `trinity-skills` **v0.3.0** (fresh-install seed only). The catalog gains `update-dashboard`, the playbook the metrics tiles already point users at, and drops the four retired `add-*` installers (now marketplace-only), giving 38 skills. The guard floor rises to v0.3.0, and `docs/user-docs/automation/skills-and-playbooks.md` joins `.env.example` in the parity check. Existing instances keep their row (ent#529); that user doc now carries the steps for moving one to a newer tag (`PUT /api/skills/sources/{id}`, then a full sync). | | 2026-09-30 | **ent#672**: the listing the sync produces now carries each skill's lifecycle keys — `deprecated` and `superseded_by` (the library's `superseded-by`) — parsed on every listing, never persisted, so a re-sync that drops the key clears the flag. Contract details: [skill-injection.md](skill-injection.md). | | 2026-09-06 | **#2545 + #2550**: bundled community-catalog pin bumped to `trinity-skills` **v0.2.0** (fresh-install seed only — adds the `project-management` category, 14 skills; `.env.example` documents the same value, `tests/unit/test_2545_skill_source_pin.py` keeps them in step). Update-path tag pin now compares the tag **peeled** (`refs/tags/^{commit}`): an annotated tag's bare rev-parse is the tag object, so the unmoved bundled source was refused as `moved_tag` on every sync after the first (`tests/unit/test_2550_annotated_tag_pin.py`, both tag kinds). | | 2026-07-29 | **ent#236 lifecycle automation**: scheduled leader-locked auto-sync, commit-gated fleet-wide re-inject with an honest per-agent report, durable sync status (`--workers 2` gap), and the dedicated range-validated `GET/PUT /api/settings/skills-library` route. Removal-on-unassign is documented in [skill-injection.md](skill-injection.md). | From 70693043ef2e1b3ae66139f1d91b48c3de41aecf Mon Sep 17 00:00:00 2001 From: Andrii Pasternak <44377756+AndriiPasternak31@users.noreply.github.com> Date: Tue, 6 Oct 2026 23:48:44 +0100 Subject: [PATCH 8/8] docs(skills): the per-source caveat covers scheduled auto-sync too; index row wording (#3123) --- docs/memory/feature-flows.md | 2 +- docs/user-docs/automation/skills-and-playbooks.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/memory/feature-flows.md b/docs/memory/feature-flows.md index 453a08cf21..cb1860991c 100644 --- a/docs/memory/feature-flows.md +++ b/docs/memory/feature-flows.md @@ -23,7 +23,7 @@ | Date | ID | Change | Flow | |------|-----|--------|------| -| 2026-10-06 | #3123 | chore(skills): **fresh installs seed the bundled community skills catalog at `trinity-skills` v0.3.0** (was v0.2.0). The tag adds `update-dashboard`, the playbook the metrics tiles already name, and drops the four retired `add-*` installers (marketplace-only now): 38 skills. `config.DEFAULT_SKILL_SOURCE_REF`, `.env.example` and the user doc move together; `tests/unit/test_2545_skill_source_pin.py` raises its floor to v0.3.0 and adds the user doc to its parity checks. The user doc gains the steps for moving an existing instance's bundled row to a newer tag (existing installs keep their row; ent#529). No runtime code change: the seed and the annotated-tag peel (#2550) already handle the tag. | [skills-library-sync.md](feature-flows/skills-library-sync.md) | +| 2026-10-06 | #3123 | chore(skills): **fresh installs seed the bundled community skills catalog at `trinity-skills` v0.3.0** (was v0.2.0). The tag adds `update-dashboard`, the playbook the metrics tiles already name, and drops the four retired `add-*` installers (marketplace-only now): 38 skills. `config.DEFAULT_SKILL_SOURCE_REF`, `.env.example` and the user doc move together; `tests/unit/test_2545_skill_source_pin.py` raises its floor to v0.3.0 and adds the user doc to its parity checks. The user doc gains the steps for moving an existing instance's bundled row to a newer tag (existing installs keep their row; ent#529). No runtime code change beyond the default: the seed and the annotated-tag peel (#2550) already handle the tag. | [skills-library-sync.md](feature-flows/skills-library-sync.md) | | 2026-10-05 | ent#752 | feat(gate): **a gated skill is refused inside the agent unless its run was approved for it** (Claude Code only). A PreToolUse hook on `Skill` and on `Agent`/`Task` skill preloads (`/opt/trinity/hooks/skill-gate.py`, its own managed-settings drop-in, exec form) asks `POST /api/skill-gate/check` with the agent's own key; the run is cleared by #751's approved-run record or a new `self_approved` record written where a self-approval lets a run through (no migration). No answer → a root-owned marker decides (gated agents fail closed, others keep working); never exit 1. A self-approved `/chat` turn runs in its own session; `/health` reports `skill_gate_hook` | [skill-gate.md](feature-flows/skill-gate.md) | | 2026-10-05 | ent#568 | feat(delegation): **every caller is taught that a receipt means the work is running — never re-send on silence**. One text (`DELEGATION_CONTRACT`, byte-identical in `platform_prompt_service.py` and `src/mcp-server/src/delegation_contract.ts`) is spliced into the platform prompt's §Agent Collaboration and published verbatim in the `chat_with_agent` and every `chat_with_` description; `fan_out` / `send_message` repeat its rule sentence. Every `chat_with_*` `execution_id` receipt carries "Do not re-send: read the outcome with `get_execution_result(…)`", and the backend's REST "poll GET" receipts are rewritten with liveness-neutral leads. Each carrying description stays under Claude Code's 2,048-char cap — `chat_with_agent` had been cut there since #2958 | [mcp-orchestration.md](feature-flows/mcp-orchestration.md), [system-wide-trinity-prompt.md](feature-flows/system-wide-trinity-prompt.md), [mcp-agent-exposure.md](feature-flows/mcp-agent-exposure.md) | | 2026-10-03 | #3185 | feat(a2a): **the outbound client speaks 402 — a priced remote is an outcome, not an outage**. `_read_capped` collapsed every HTTP ≥ 400 into `rpc_http_error` without reading the body, so a remote answering 402 was unreachable: the caller saw neither the price nor a way to attach a token. 402/403 on the RPC hop are now classified BEFORE the encoding and length guards (a gzipped or oversized "pay me" read as an outage), both rails are read (the HTTP 402's `payment-required` header or body, and an in-band `x402.payment.status` task — checked before `_parse_task` on send AND poll, or a priced `input-required` reaches the agent as a prompt it polls forever), and the route answers **402** with an allowlisted `detail.payment` = `{summary, x402, truncated}`, scrubbed against the token, its base64 forms and its decoded leaves. `payment_rejected` / `rpc_forbidden` stay 502 with `remote_status`, so 402 ("buy") is always distinguishable from 403 ("top up"). The endpoint credential carries a `credential_kind` (`api_key` default — every pre-#3185 record — or `payment_token`, inferred from the value when omitted with the SAME predicate the client sends on), an x402 v3 token is flagged `credential_single_use` rather than refused, and the MCP tools return `payment_required` + `payment` + `task_id` + `do_not_retry` with a description that names who can act. Trinity never buys, never retries a priced call, and never snapshots a 402 — a stored one would replay "pay me" after the operator paid | [a2a-outbound-call.md](feature-flows/a2a-outbound-call.md), [architecture/backend.md](architecture/backend.md), [architecture/mcp-server.md](architecture/mcp-server.md) | diff --git a/docs/user-docs/automation/skills-and-playbooks.md b/docs/user-docs/automation/skills-and-playbooks.md index cd2929197d..c36b25d083 100644 --- a/docs/user-docs/automation/skills-and-playbooks.md +++ b/docs/user-docs/automation/skills-and-playbooks.md @@ -58,7 +58,7 @@ Skills carry executable `scripts/`, and library automation can push them to your - No such row (an instance migrated from the legacy single-repository setting, or one where the bundled source was removed): add the catalog as a custom source pinned to the tag instead (Settings → **Track: Tag**). - The row is disabled: enable it. 3. **Change the ref.** `PUT /api/skills/sources/{id}` with `{"ref": ""}`. Changing the ref resets the source's sync status to `never`. - 4. **Sync the whole library.** Use **Sync all** in the Settings skill-sources panel or **Sync now** on the Library's Skills tab (both call `POST /api/skills/library/sync`), not the per-source **Sync** button. Only the full sync starts the fleet re-inject, and only when automatic re-inject is on; a per-source sync leaves running agents on their old files. If a per-source **Sync** has already run on the new tag, the full sync finds that source unchanged and starts no re-inject (unless another source also moved) — restart the affected agents, since an agent's skills are delivered again when it starts, or re-deliver one agent's skills with `POST /api/agents/{name}/skills/inject`. If scheduled auto-sync is enabled, it also picks up the change on its next run and may re-inject across the fleet. + 4. **Sync the whole library.** Use **Sync all** in the Settings skill-sources panel or **Sync now** on the Library's Skills tab (both call `POST /api/skills/library/sync`), not the per-source **Sync** button. Only the full sync starts the fleet re-inject, and only when automatic re-inject is on; a per-source sync leaves running agents on their old files. If scheduled auto-sync is enabled, it also picks up the change on its next run and may re-inject across the fleet. If a per-source **Sync** has already run on the new tag, a full sync — manual or scheduled — finds that source unchanged and starts no re-inject (unless another source also moved) — restart the affected agents, since an agent's skills are delivered again when it starts, or re-deliver one agent's skills with `POST /api/agents/{name}/skills/inject`. 5. **Check.** Confirm the skills you expect from the new tag are in the Library (for `v0.3.0`, `update-dashboard`). **Rollback:** the same `PUT` with the `ref` you noted, then sync the whole library again. Any agent assigned a skill that only the newer tag carries will then report it missing.