Skip to content

Workspace Skills Mount (cross-runtime customization)

Status: Open — design proposal (Phase 5, Agent Orchestrator Research Program)

Today, an role’s behavior is locked at image build time: the Dockerfile installs whatever plugins/skills/MCP servers, the jackin.role.toml declares Claude plugins, and that’s that. Operators who want to customize behavior per-workspace (different skill set per project) or operators who want to share skills across multiple agent classes (one team’s “code style” instructions used by Claude and Codex and Amp) have no clean path.

multicode addresses this with add-skills-from: directories under configured paths get bind-mounted into the agent’s runtime config dir (~/.config/opencode/skills/<name>/). The agent picks them up at runtime; no rebuild needed. Operators can edit a skill in their normal editor and the next agent invocation sees the change.

  • It’s the right shape for team-level customization that doesn’t belong in either the role repo or the operator’s personal config.
  • It’s runtime-agnostic by design — the same skill markdown bind-mounts into Claude’s, Codex’s, or Amp’s expected skills directory based on the runtime adapter.
  • It complements (doesn’t replace) the custom plugin marketplace story (now shipped — see the role manifest reference): marketplaces distribute reusable skills published broadly; the workspace skills mount handles local / team-specific skills the operator doesn’t want to publish.
  • It gives the tag protocol a natural distribution channel: jackin’ can ship a skill bundle that roles pull in via this mount, and operators see the protocol “for free” without having to install plugins per role.
  • It also supports workflow and playbook skills such as “independent fix”, “address review feedback”, or “prepare a PR”, which are often more valuable to a queue-driven operator than stack syntax hints.

Sources:

[isolation]
add-skills-from = [
"./workspace-skills",
"~/team-skills/micronaut",
]

For each path, every immediate subdirectory becomes a skill: the subdirectory is bind-mounted to ~/.config/opencode/skills/<dir-name>/ inside the workspace’s isolate. The skill’s SKILL.md (frontmatter + body) is what OpenCode reads.

The contents in their repo (visible in workspace-skills/):

  • git-commit-coauthorship/ — commit attribution rules
  • independent-fix/ — fix workflow
  • java-install/ — Java version selection
  • machine-readable-issue|clone|pr/ — tag-protocol emission
  • micronaut-projects-guide/ — toolchain hints

The runtime-agnostic version: each runtime adapter owns the destination inside the container; jackin’ owns the source selection and bind-mount plumbing.

# Operator-level (cross all workspaces) or workspace-level — both
# accepted, with workspace overriding operator on path conflict.
[skills]
add_from = [
"~/team-skills/jackin-protocols",
"~/dotfiles/agent-skills",
]
# Or per-workspace:
[workspaces.fix-bugs.skills]
add_from = ["./project-specific-skills"]

Each path’s immediate subdirectories are skills. Each skill has a SKILL.md at its root (the same structure multicode uses, the same structure Claude / Codex / Amp converge on).

Each runtime adapter declares where skills go inside the container:

  • Claude/home/agent/.claude/plugins/jackin-skills/<name>/ (works alongside the existing [claude.plugins] install path; jackin treats workspace skills as a special pre-installed plugin namespace).
  • Codex/home/agent/.codex/skills/<name>/
  • Amp/home/agent/.config/amp/skills/<name>/

If a runtime doesn’t support a skills concept natively, the adapter mounts at a known path and the role’s entrypoint (or a small adapter shim) is responsible for surfacing it. V1 punts on this case — all three planned runtimes (Claude, Codex, Amp) have a skills concept.

Per-path (operator + workspace) order is additive: the operator’s list is read first, the workspace’s list is appended. Within the combined list, the last declaration of a skill name wins (later overrides earlier). This is documented behavior, not implicit.

If a skill name collides with one installed via the manifest’s [claude.plugins] (or the per-runtime equivalent), jackin’ refuses to launch with a clear error — the operator chooses which to keep. Silent override here is too dangerous.

Default: read-only mount. The agent reads its skills; doesn’t modify them. Operators editing skill markdown in their editor see changes on next agent restart.

Optional: read_write = true for the rare case where a skill itself captures state (a “remember-this” skill). Not encouraged; documented as opt-in.

  • [skills] block at operator and workspace levels with add_from list.
  • Per-runtime mount destination owned by each runtime adapter.
  • Conflict resolution: workspace appends operator; later overrides earlier; manifest-level conflicts error.
  • Read-only by default; opt-in read_write.
  • New repo jackin-project/jackin-skills ships a published bundle including the tag protocol emission skills.
  • Skill version pinning. Skills are filesystem paths; pin the path, not a version. If versioning becomes important, revisit.
  • Skill marketplace integration (browse/install via TUI). The shipped custom plugin marketplace support (see the role manifest reference) handles published skills; this mount is for local/team ones.
  • Cross-runtime skill format conversion. V1 assumes the markdown format is portable (frontmatter + body); if Claude / Codex / Amp diverge, the runtime adapter handles per-runtime tweaks. Defer active conversion until a divergence shows up.
  • Per-role skill enable/disable from the same add_from list. V1 mounts everything; roles that don’t want a skill can ignore it by name.
  • Should workspace skills mount into Claude as “plugins” or “skills”? Claude Code’s plugin format is heavier; “skills” via Claude’s skills feature is closer to the multicode shape. Recommended: use Claude skills; the multi-runtime work needs to confirm Claude’s skills plumbing matches.
  • Skills inside per-mount-isolated worktrees. If add_from references a path inside an isolated workspace mount, the materialized worktree gets the skill inside the container and the bind-mount duplicates it — confusing. Recommended: reject add_from paths that resolve under an isolated workspace mount, with a clear error.
  • Default skill bundle for jackin’. Should jackin-project/jackin-skills be auto-mounted by default when an operator opts into the <jackin:*> tag protocol? Recommended: no auto-mount; operators add it explicitly. Avoids surprise.
  • New module (e.g. src/skills.rs) — collection + validation
  • src/runtime/launch.rs — bind-mount plumbing
  • Per-runtime adapter modules (Claude / Codex / Amp) — each owns its mount destination
  • New repo jackin-project/jackin-skills — published bundle
  • New docs page: docs/src/content/docs/guides/skills.mdx