Skip to content

feat(multi-agent): install a skill once and share it across agents#11

Merged
vladtara merged 2 commits into
mainfrom
007-multi-agent-sync
Jun 30, 2026
Merged

feat(multi-agent): install a skill once and share it across agents#11
vladtara merged 2 commits into
mainfrom
007-multi-agent-sync

Conversation

@vladtara

Copy link
Copy Markdown
Contributor

Summary

Introduces a three-layer install model so the same skill is resolved and stored once and shared by every AI agent that targets it:

.gskill/store/<algo>/<hash>   immutable canonical content — one physical copy
        ▲ symlink (copy fallback)
.agents/skills/<name>          active project skill — one entry per installed skill
        ▲ symlink (copy fallback)
.claude/skills/<name>  .codex/skills/<name>  …   per-agent targets

Adding an agent to a skill creates only the missing link — no re-download, no duplicate content. Store + active layer are gitignored and regenerated by gskill sync.

What's new

  • internal/active layer; the installer routes activation through it (store → active → agent).
  • Declarative gskill sync — reconciles disk to the manifest's desired state: idempotent, drift-aware, desired-aware --prune, legacy migration.
  • gskill status (per-skill, per-agent mode + health) and gskill unlink (retain-unless-prune on the last agent).
  • Chain-aware check/repair over a shared health model.
  • Install mode --symlink / --copy / --auto (default auto).
  • Lockfile records active_path (schema stays v1, additive).

Security & integrity hardening

Addresses an adversarial review of the branch:

  • Prune/unlink/remove deletions are confined to adapter-derived, in-bounds paths; out-of-bounds lockfile paths are skipped + warned, never deleted.
  • EnsureActive fails closed on foreign content instead of overwriting it.
  • check/repair hash-verify the store and copy targets and fail closed (exit 6) on tampering.
  • Adding an agent activates only the new agents and resolves nothing (works offline).

Testing

./scripts/verify.sh passes (fmt, vet, golangci-lint, -race tests + coverage, govulncheck, gitleaks). New unit + integration coverage includes an adversarial_test.go suite (malicious lock path, corrupt store, corrupt copy, foreign active entry, offline agent-add) — each exercises behavior that was broken before this change.

Introduce a three-layer install model (content store → .agents/skills
active layer → per-agent targets) so a skill is resolved and stored once
and shared by every agent that targets it. Adding an agent creates only
the missing link — no re-download, no duplicate content.

- new internal/active layer; the installer routes activation through it
- declarative `gskill sync` reconciles disk to the manifest: idempotent,
  drift-aware, desired-aware --prune, and legacy migration
- `gskill status` and `gskill unlink` (retain-unless-prune on the last agent)
- chain-aware `check`/`repair` over a shared health model
- auto install mode (--symlink/--copy/--auto), default auto
- lockfile records active_path (schema stays v1, additive)

Security & integrity hardening:
- confine prune/unlink/remove deletions to adapter-derived, in-bounds
  paths; out-of-bounds lockfile paths are skipped, never deleted
- EnsureActive fails closed on foreign content instead of overwriting it
- check/repair hash-verify the store and copy targets and fail closed (exit 6)
- adding an agent activates only the new agents and resolves nothing
Copilot AI review requested due to automatic review settings June 29, 2026 13:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements a multi-agent “install once, share everywhere” model by introducing a project-level active layer that sits between the content-addressed store and per-agent skill targets. This enables gskill sync to reconcile desired agent targeting without re-downloading content, and adds new operational commands (status, unlink) plus chain-aware health/check/repair behavior.

Changes:

  • Add the active layer (.agents/skills/<name>) and extend installer/lockfile to record active_path and per-agent modes.
  • Rework gskill sync to be manifest-driven reconciliation (with --prune / orphan reporting) and add gskill status + gskill unlink.
  • Add chain health evaluation and broaden integration/unit coverage, including adversarial tests.

Reviewed changes

Copilot reviewed 35 out of 35 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
test/integration/sync_reconcile_test.go Integration coverage for manifest-driven sync reconcile, idempotency, prune, and legacy migration.
test/integration/status_unlink_test.go Integration coverage for status JSON + unlink behaviors (retain vs prune).
test/integration/multi_agent_share_test.go Integration coverage for install-once/share behavior, default agent, collision, and mode flags.
test/integration/check_repair_chain_test.go Integration coverage for chain-aware check/repair including drift and store corruption.
test/integration/adversarial_test.go Integration adversarial scenarios: lockfile path escape, foreign active entry, corrupt store/copy, offline agent-add.
test/integration/adapter_extensibility_test.go Integration proof that adding a new agent adapter works end-to-end with the new active-layer model.
README.md Document multi-agent sharing, new commands, and updated sync semantics.
internal/lockfile/testdata/lock.golden Update golden lockfile fixture to include active_path and per-agent modes.
internal/lockfile/lockfile.go Extend Installation with ActivePath and clarify semantics in comments.
internal/lockfile/lockfile_golden_test.go Update lockfile golden test sample to include ActivePath/Modes.
internal/lockfile/consistency.go Add consistency check to ensure manifest-declared agents are present in the lock.
internal/lockfile/consistency_test.go Add tests for agent-set drift and superset acceptance.
internal/installer/types.go Introduce install mode preferences: auto (default), symlink, copy.
internal/installer/installer.go Route activation through the active layer and record ActivePath; add agent activation behavior for link/copy modes.
internal/installer/installer_test.go Assert the new “store → active → agent” symlink chain.
internal/cli/unlink.go New CLI command wiring for gskill unlink.
internal/cli/sync.go Change sync to manifest-desired reconciliation, with richer JSON output and up-to-date reporting.
internal/cli/status.go New CLI command wiring for gskill status.
internal/cli/root.go Register new commands and update help strings for sync.
internal/cli/add.go Add --auto mode and adjust install-mode flag parsing/help.
internal/app/unlink.go Implement unlinking a single agent from a skill, with optional prune/GC behavior.
internal/app/sync.go Rewrite sync as manifest-driven reconcile, including desired agent sets, orphans, pruning, and lock updates.
internal/app/status.go Implement read-only per-skill/per-agent status report using the shared health model.
internal/app/repair.go Repair now uses the shared chain-health evaluation to decide what to re-materialize.
internal/app/paths.go Add confined deletion helpers to prevent lockfile-driven out-of-bounds deletions.
internal/app/lifecycle.go Update remove flow to use confined target deletion and remove active-layer entries.
internal/app/install.go Add local “agent-add” fast path, plan/merge semantics, and manifest agent unioning.
internal/app/inspect.go Make check chain-aware and fail-closed on integrity faults.
internal/app/health.go New chain health model (store/active/agent targets), with hash verification for integrity faults.
internal/app/health_test.go Unit tests for the chain health evaluator (missing/broken/corrupt/legacy).
internal/app/gitignore_test.go Verify init gitignores both .gskill/ and .agents/.
internal/active/doc.go Package docs for the active-layer model.
internal/active/active.go Active-layer management: ensure, health, remove, list; fail-closed on foreign occupants.
internal/active/active_test.go Unit tests for active-layer behaviors (idempotent, repoint, fail-closed, list/remove).
docs/reference/commands.md Update CLI reference for new flags/commands and revised sync semantics.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/app/unlink.go
Comment on lines +55 to +59
locked, inLock := lf.Skills[skill]
ms, inManifest := m.Skills[skill]
if !inLock && !inManifest {
return fmt.Errorf("%w: skill %q is not declared", errs.ErrInvalidManifest, skill)
}
Comment thread internal/installer/installer.go Outdated
Comment on lines +321 to +325
if linkErr := os.Symlink(abs, dest); linkErr == nil {
return ModeSymlink, nil
}
if err := fsutil.CopyDir(copySource, dest); err != nil {
return "", fmt.Errorf("copy fallback: %w", err)
- unlink: a skill present in only the manifest or only the lockfile is a
  lock mismatch (exit 4), not a half-edit that writes a zero-value entry
- installer: --symlink is now strict — it fails instead of silently
  copying when a symlink can't be created, so policy/permission failures
  surface; only --auto (and symlink-incapable agents) fall back to a copy
@vladtara
vladtara merged commit e20beb5 into main Jun 30, 2026
8 checks passed
@vladtara
vladtara deleted the 007-multi-agent-sync branch June 30, 2026 10:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants