feat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecar - #108

Merged
khaliqgant merged 8 commits into
mainfrom
persona-maker-mount-mcp-guidance
May 13, 2026
Merged

feat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecar#108
khaliqgant merged 8 commits into
mainfrom
persona-maker-mount-mcp-guidance

Conversation

@khaliqgant

@khaliqgantkhaliqgant commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

The persona-maker built-in was missing teaching content for mount, mcpServers, and the silent-footgun distinction between claudeMd (path) and claudeMdContent (inline). A persona authored against the existing spec hit four real failure modes:

  1. claudeMdContent: \"web-blog-content-writer.claudeMdContent.md\" — filename string written verbatim as CLAUDE.md body (dry-run green, agent boots with no spec).
  2. mount.ignoredPatterns: [\"**\", \"!./web/**\"]** breaks ! re-includes; empty mount.
  3. readonlyPatterns: [\"web/**\"] on the persona's own work directory — writes silently dropped on sync-back.
  4. model: \"claude-sonnet\" — bare alias without version, harness errors at spawn.

Changes

New filepersonas/persona-maker.md — the persona's full operating spec, including dedicated sections for Relayfile mount policy (allow-list idiom, the non-obvious !web vs !web/ walker bug, readonlyPatterns scope rule, per-agent dotfile overlay, .git sandbox behavior), MCP servers (two spec variants, \$VAR secret substitution, claude/codex/opencode support matrix, permissions.allow pairing), and Persona sidecar fields (path-vs-inline distinction with explicit "dry-run does NOT catch this" callout).

persona-maker.json:

  • Replaces inline agentsMdContent with agentsMd: \"./persona-maker.md\" (path form). The catalog generator at packages/workload-router/scripts/generate-personas.mjs inlines the .md content into the published spec at build time, so the package still ships a single bundled JSON.
  • New rules in the body: full model identifiers (claude-sonnet-4-6 not claude-sonnet).
  • Anti-goals extended with the four lessons learned plus the mount allow-list !dir (no slash) rule.

Regeneratedpackages/workload-router/src/generated/personas.ts. agentsMdContent is now 25,371 chars and contains all three sections, ready to ship.

Design history

Earlier iterations tried two paths that don't survive cross-repo invocation:

  • Inlining everything in agentsMdContent (one giant escaped string): worked but unmaintainable.
  • Extracting to three local personas/skills/*.md files referenced via local/<name> source paths (the proactive-agents pattern): worked from inside the workforce repo, failed everywhere else. Local skill sources resolve relative paths against process.cwd() at install time; the .md files don't exist in user repos, so cp fails. Reproduced from /tmp/: ✗ 3 of 4 skill(s) failed.

The proactive-agents pattern works because both the persona AND the skill files are co-located in the user's own repo. Persona-maker is a built-in shipped via npm — same pattern doesn't carry.

The agentsMd sidecar approach gets the maintainability win (editable .md file with proper markdown structure) without the cross-repo failure: the generator already inlines the sidecar at build time and the harness loads AGENTS.md from the session cwd, with no runtime filesystem lookups against unfamiliar directories.

Test plan

  • node -e \"require('./personas/persona-maker.json')\" parses; agentsMd resolved to ./persona-maker.md.
  • Catalog generator inlines: published agentsMdContent now 25,371 chars with ## Relayfile mount policy, ## MCP servers, ## Persona sidecar fields.
  • Dry-run from /tmp/ (non-workforce cwd) — the case that previously failed: ✓ dry-run ok: 1 skill(s) installed cleanly.
  • Companion fix in relayfile for the trailing-slash negation walker bug: fix(local-mount): trailing-slash negations now re-include allow-listed directories relayfile#145.

To test locally after merge

The published agentworkforce@3.0.3 on PATH won't pick this up until the next release. To test now:

```bash
cd ~/Projects/AgentWorkforce/workforce
git pull
corepack pnpm install
corepack pnpm --filter @agentworkforce/workload-router --filter @agentworkforce/cli build

From any directory:

node ~/Projects/AgentWorkforce/workforce/packages/cli/dist/cli.js agent persona-maker
```

🤖 Generated with Claude Code

persona-maker.json's AGENTS.md sidecar only listed `mount` and
`mcpServers` as optional fields without explaining when to use them,
the shape, or how harness selection is constrained by MCP support.
Authored personas needing filesystem sandboxing or MCP wiring were a
coin-flip on getting these blocks right.
- Add a `mount` section covering ignoredPatterns/readonlyPatterns
semantics, the `.{persona.id}.agentignore` overlay behavior keyed off
`agentName: persona.id`, the gitignore-negation idiom for allow-lists,
the file-scope-vs-tool-scope split from `permissions`, and the
auto-`.git` sandbox behavior.
- Add an `mcpServers` section with the two spec variants (http/sse vs
stdio), an example of each, `$VAR` substitution policy, and the
claude / codex / opencode support matrix so harness selection is
informed when MCP is required.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR externalizes the persona authoring specification from an inline agentsMdContent field in personas/persona-maker.json into a dedicated personas/persona-maker.md file. The new markdown document provides comprehensive, structured guidance for authoring a Workforce persona, covering required JSON schema, mount policy, MCP servers, sidecar fields, runtime configuration, validation workflow, built-in catalog integration, and explicit anti-goals.

Changes

Persona authoring specification

Layer / File(s)Summary
Persona JSON refactoring and schema foundation
personas/persona-maker.json, personas/persona-maker.md
The JSON file now references ./persona-maker.md instead of embedding agentsMdContent. The new guide introduces required persona JSON shape including id/intent, metadata (tags, description, skills), runtime fields (harness, model, systemPrompt, harnessSettings), and prompt authoring constraints.
Mount policy specification
personas/persona-maker.md, personas/skills/persona-relayfile-mount/SKILL.md
Specifies the mount JSON shape and policy: ignoredPatterns vs readonlyPatterns, per-agent dotfile overlays (.{id}.agentignore/.{id}.agentreadonly), gitignore-style allow-list rules with non-obvious negation requirements, .git sync behavior, and a detailed pre-handoff checklist.
MCP servers specification
personas/persona-maker.md, personas/skills/persona-mcp-servers/SKILL.md
Documents mcpServers configuration including uniform server spec, remote http/sse vs local stdio variants, $VAR/${VAR} secret substitution and unset behavior, harness support matrix, permissions pairing via mcp__* keys, and an MCP authoring checklist.
Sidecar markdown fields specification
personas/persona-maker.md, personas/skills/persona-sidecars/SKILL.md
Defines sidecar fields (claudeMd/agentsMd vs *MdContent), path vs inline semantics and the silent-failure footgun when *MdContent is used incorrectly, *MdMode options (overwrite/extend), and a sidecar authoring checklist.
Runtime, validation, and authoring workflow
personas/persona-maker.md
Lays out runtime defaults for harness, model, reasoning, and timeoutSeconds, describes skill discovery/curation and required agentworkforce agent <id> --dry-run validation checks, details persona prompt authoring steps and built-in catalog integration, lists anti-goals, and specifies the handoff contract.
Skills package manifest, README & LICENSE
personas/skills/prpm.json, personas/skills/README.md, personas/skills/LICENSE
Adds agentworkforce-persona-authoring-skills manifest registering three skills and includes README and MIT license for the skills package.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested reviewers

  • willwashburn

Poem

🐰 The spec hops free from JSON's nest,

A markdown tome emerges dressed,
Mounts and MCPs set in lines,
Sidecars, checklists, clear design,
Persona makers, now you're blessed.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title accurately summarizes the main change: adding guidance documentation for mount/MCP/sidecar features via a persona-maker.md sidecar file referenced in agentsMd.
Description check✅ PassedThe description clearly relates to the changeset, explaining the four failure modes being fixed, the new teaching content added, design decisions, and test plans.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch persona-maker-mount-mcp-guidance

Comment @coderabbitai help to get the list of available commands and usage tips.

@devin-ai-integrationdevin-ai-integrationBot 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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

…ills
The mount and MCP additions from the previous commit made agentsMdContent
even longer. Extract them — plus the silent-footgun guidance about
claudeMdContent vs claudeMd — into three local skill .md files matching
the proactive-agents skill-loading pattern. The skills install into the
session via the local source-kind, so the persona reads them as standalone
SKILL.md files in its working dir instead of carrying everything inline.
Skills:
- personas/skills/relayfile-mount.md — mount field deep dive: allow-list
idiom (/* not **, paired !dir/ + !dir/**), readonlyPatterns scope rule
(never the work dir), agentName overlay, .git sandbox behavior.
- personas/skills/persona-mcp-servers.md — mcpServers two variants
(http/sse vs stdio), $VAR substitution, claude/codex/opencode support
matrix, permissions.allow pairing.
- personas/skills/persona-sidecars.md — claudeMd (path) vs claudeMdContent
(inline) distinction; calls out that the dry-run does NOT catch a path
string mistakenly stored in *MdContent.
persona-maker.json:
- skills[] now declares the three local skills alongside skill.sh/find-skills.
- agentsMdContent trimmed: the long mount/MCP/sidecar paragraphs are
replaced with one-line skill pointers. Net length: 15985 → 15318 chars.
- Anti-goals extended with the four lessons from a recent broken persona:
filename string in *MdContent; ** as broad mount exclude; readonly on
work dir; opencode + mcpServers; bare model alias without version.
- Added 'full model identifiers' rule (claude-sonnet-4-6, not claude-sonnet).
Regenerated packages/workload-router/src/generated/personas.ts to pick up
the new skills.
Dry-run: ✓ 4 skill(s) installed cleanly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgantkhaliqgant changed the title docs(persona-maker): teach mount policy and mcpServers shapefeat(persona-maker): mount/MCP/sidecar guidance as local skillsMay 13, 2026
The "obvious" gitignore allow-list `["/*", "!web/", "!web/**"]` silently
produces an empty mount. Reproduced against relayfile's createMount:
mount root contained only CLAUDE.md, _MOUNT_README.md, and .relayfile-local-mount
— no web/.
Root cause in relayfile-local-mount/src/mount.ts isPathMatched():
return matcher.ignores(relPath) || (isDirectory && matcher.ignores(`${relPath}/`));
The OR short-circuits. For a directory `web`:
- matcher.ignores('web') → true (`/*` matches the bare name)
- matcher.ignores('web/') → false (`!web/` negates the trailing-slash form)
but this branch is never reached.
So `!web/` (slash) only counters the trailing-slash form, leaving the
bare-name check unopposed. The walker treats `web` as ignored and skips
recursion. Verified by harness:
/* + !web/ + !web/** → web (dir) reported as ignored: true (broken)
/* + !web + !web/** → web (dir) reported as ignored: false (correct)
Confirmed end-to-end against a real createMount: with `!web` the mount
root contains web/content/post.md as expected.
Updates:
- relayfile-mount.md skill: add a fourth rule explicitly calling out the
`!dir` vs `!dir/` distinction with the walker's short-circuit as the
reason, plus a "wrong / right" side-by-side. Update the checklist line.
- persona-maker.json anti-goal: replace `!dir/` reference with `!dir`
plus the reason.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitaicoderabbitaiBot 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.

🧹 Nitpick comments (1)
personas/skills/relayfile-mount.md (1)

32-33: 💤 Low value

Consider clarifying the placeholder notation.

The .{id} notation could be more explicit that it's a placeholder. For an AI agent consuming this skill, consider using .${id} or adding a concrete example like "For a persona with id: blog-writer, the dotfile would be .blog-writer.agentignore."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@personas/skills/relayfile-mount.md` around lines 32 - 33, The placeholder
notation `.{id}.agentignore` and `.{id}.agentreadonly` is ambiguous; update
these entries to use a clearer placeholder like `.${id}.agentignore` and
`.${id}.agentreadonly` or add a concrete example line (e.g., for `id:
blog-writer` show `.blog-writer.agentignore`) so readers and agents understand
that `{id}` is substituted with the persona id.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@personas/skills/relayfile-mount.md`:
- Around line 32-33: The placeholder notation `.{id}.agentignore` and
`.{id}.agentreadonly` is ambiguous; update these entries to use a clearer
placeholder like `.${id}.agentignore` and `.${id}.agentreadonly` or add a
concrete example line (e.g., for `id: blog-writer` show
`.blog-writer.agentignore`) so readers and agents understand that `{id}` is
substituted with the persona id.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 51803e8c-d30a-4235-a2b0-74028ad47bff

📥 Commits

Reviewing files that changed from the base of the PR and between dc4ec59 and bfe36f5.

⛔ Files ignored due to path filters (1)
  • packages/workload-router/src/generated/personas.ts is excluded by !**/generated/**
📒 Files selected for processing (4)
  • personas/persona-maker.json
  • personas/skills/persona-mcp-servers.md
  • personas/skills/persona-sidecars.md
  • personas/skills/relayfile-mount.md
✅ Files skipped from review due to trivial changes (2)
  • personas/skills/persona-sidecars.md
  • personas/skills/persona-mcp-servers.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • personas/persona-maker.json

The previous extraction-into-local-skills approach was broken in the
field. Reported live: persona-maker spawned from a non-workforce cwd
(e.g. ../relay) only loaded `find-skills` — the three local skills
`relayfile-mount`, `persona-mcp-servers`, `persona-sidecars` were
missing from opencode's Skills picker.
Two layered bugs:
1. The agentworkforce binary on PATH is the published 3.0.3 from npm.
Its baked-in catalog has the old persona-maker (only find-skills).
New skills aren't visible until a release lands.
2. Even with the local CLI build, local skill sources resolve relative
paths against process.cwd() at install time. When invoked from
`/tmp/` or any non-workforce repo, `cp personas/skills/<x>.md ...`
fails because the .md files only exist in the workforce source repo.
Three of four skill installs fail with exit code 1.
The proactive-agents pattern (local/<name> source paths) works there
because both the persona AND its skill .md files are co-located in
the same user-repo. Persona-maker is a BUILT-IN shipped via npm —
that pattern doesn't carry across.
Fix: use the agentsMd path-form sidecar. The catalog generator at
`packages/workload-router/scripts/generate-personas.mjs` already
inlines sidecar .md content into agentsMdContent at build time, so
the published package ships a single bundled spec. The .md file is a
real markdown file the author can edit ergonomically; the user sees
the full content in AGENTS.md at session start with no runtime
filesystem lookups required.
Changes:
- New: personas/persona-maker.md — full operating spec including the
Relayfile mount, MCP servers, and Persona sidecar sections that were
previously split into local skill files. Same content the generator
would have inlined; consolidated into one file because cross-cwd
resolution made splitting unworkable.
- personas/persona-maker.json: replace agentsMdContent (inline) with
agentsMd (./persona-maker.md). Drop the three local/ skill entries
from skills[]; only skill.sh/find-skills remains.
- Delete personas/skills/* — content lives in persona-maker.md now.
- Regenerated packages/workload-router/src/generated/personas.ts;
agentsMdContent now 25,371 chars with all three sections inlined.
Verified: dry-run green from /tmp (non-workforce cwd) — the
cross-repo case that previously produced 3 of 4 failed installs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgantkhaliqgant changed the title feat(persona-maker): mount/MCP/sidecar guidance as local skillsfeat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecarMay 13, 2026
Ricky Schema Cascadeand others added 4 commits May 13, 2026 14:04
…m.dev
Previous iterations tried inlining everything in agentsMdContent and then
extracting to local skill .md files referenced via repo-relative paths.
The local-path approach broke cross-repo invocation because local skill
sources resolve against process.cwd() at install time, not the workforce
package install root. Confirmed live: persona-maker spawned from
/Users/khaliqgant/Projects/AgentWorkforce/relay only saw skill.sh/find-skills
in the opencode picker.
Fix: publish the three skills as prpm packages so they're installable from
any cwd via npx -y prpm install <ref>.
Package layout (personas/skills/):
- prpm.json — multi-package manifest following the
@prpm/prpm-json-best-practices-skill structure: top-level metadata
(name, version, author, license, repository, organization), plus a
packages[] with three skill entries (format: generic, subtype: skill).
- LICENSE — MIT, picked up automatically by prpm publish for all packages.
- README.md — discovery / install docs.
- persona-relayfile-mount/SKILL.md — mount field deep dive: allow-list
idiom, !web vs !web/ walker gotcha, readonlyPatterns scope, agentName
overlay, .git sandbox.
- persona-mcp-servers/SKILL.md — mcpServers spec variants, $VAR
substitution, claude/codex/opencode harness matrix, permissions.allow
pairing.
- persona-sidecars/SKILL.md — claudeMd (path) vs claudeMdContent (inline)
distinction; the silent footgun the dry-run does NOT catch.
persona-maker.json:
- skills[] now declares the three @agent-workforce/persona-* refs
alongside skill.sh/find-skills. They install via prpm at session start
and appear in the opencode Skills picker.
- agentsMd: ./persona-maker.md — slim sidecar restored, with the three
embedded sections replaced by pointers to the published skills.
Anti-goals updated to reference the new skill IDs.
Regenerated packages/workload-router/src/generated/personas.ts.
`prpm publish --dry-run` from personas/skills/: ✓ all 3 packages ready
to publish under @agent-workforce/ scope (khaliqgant ✓ as org member).
Publish runs separately (user-driven, not automated in this commit).
After publish lands on prpm.dev, `agentworkforce agent persona-maker
--dry-run` will install all four skills cleanly. Until then the dry-run
exercising the three new skills will fail at the prpm registry lookup
step — expected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…works
Published 1.0.0 with format: generic. Install via `npx -y prpm install
@agent-workforce/persona-relayfile-mount --as opencode` (the command
persona-kit emits for opencode-harness personas) errors with:
Failed to parse generic format: Unsupported source format for
conversion: generic
prpm has format converters keyed off the source format. `generic` has
no converter to `opencode` / `codex` / etc., so install fails the
moment the workforce CLI tries to materialize the skill.
Bump to 1.0.1 with format: claude. SKILL.md with YAML frontmatter is
canonically claude-flavored, and prpm knows how to convert claude →
opencode (verified by installing @agent-relay/choosing-swarm-patterns
with --as opencode: ✓ Converted from claude to opencode).
Dry-run validates clean for all three packages at 1.0.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…eneric
Verified after publish: `prpm show @agent-workforce/persona-relayfile-mount`
returns "Type: generic skill" at version 1.0.1, and `prpm install --as
opencode` still errors "Failed to parse generic format". Either the
publish of 1.0.1 happened before the format-change commit landed in the
working tree, or prpm caches format metadata at first publish — either
way, the remote tarball is still generic.
Bump to 1.0.2 with format: claude. Dry-run confirms:
Package: @agent-workforce/persona-relayfile-mount@1.0.2
Format: claude | Subtype: skill
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The prpm registry route now updates mutable manifest fields on republish
(format, subtype, description, tags, etc.), so the three skills finally
landed as format: claude. Verified end-to-end:
- `prpm show @agent-workforce/persona-relayfile-mount` reports Type:
claude skill at v1.0.3 (previously locked at generic from 1.0.0).
- `agentworkforce agent persona-maker --dry-run` from /tmp:
✓ dry-run ok: 4 skill(s) installed cleanly. All three new skills now
convert claude → opencode and materialize into .opencode/skills/ at
session start.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
khaliqgant merged commit a338122 into mainMay 13, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the persona-maker-mount-mcp-guidance branch May 13, 2026 12:55
Sign up for freeto 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.

1 participant

@khaliqgant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecar - #108

Merged
khaliqgant merged 8 commits into
mainfrom
persona-maker-mount-mcp-guidance
May 13, 2026
Merged

feat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecar#108
khaliqgant merged 8 commits into
mainfrom
persona-maker-mount-mcp-guidance

Conversation

@khaliqgant

@khaliqgantkhaliqgant commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

The persona-maker built-in was missing teaching content for mount, mcpServers, and the silent-footgun distinction between claudeMd (path) and claudeMdContent (inline). A persona authored against the existing spec hit four real failure modes:

  1. claudeMdContent: \"web-blog-content-writer.claudeMdContent.md\" — filename string written verbatim as CLAUDE.md body (dry-run green, agent boots with no spec).
  2. mount.ignoredPatterns: [\"**\", \"!./web/**\"]** breaks ! re-includes; empty mount.
  3. readonlyPatterns: [\"web/**\"] on the persona's own work directory — writes silently dropped on sync-back.
  4. model: \"claude-sonnet\" — bare alias without version, harness errors at spawn.

Changes

New filepersonas/persona-maker.md — the persona's full operating spec, including dedicated sections for Relayfile mount policy (allow-list idiom, the non-obvious !web vs !web/ walker bug, readonlyPatterns scope rule, per-agent dotfile overlay, .git sandbox behavior), MCP servers (two spec variants, \$VAR secret substitution, claude/codex/opencode support matrix, permissions.allow pairing), and Persona sidecar fields (path-vs-inline distinction with explicit "dry-run does NOT catch this" callout).

persona-maker.json:

  • Replaces inline agentsMdContent with agentsMd: \"./persona-maker.md\" (path form). The catalog generator at packages/workload-router/scripts/generate-personas.mjs inlines the .md content into the published spec at build time, so the package still ships a single bundled JSON.
  • New rules in the body: full model identifiers (claude-sonnet-4-6 not claude-sonnet).
  • Anti-goals extended with the four lessons learned plus the mount allow-list !dir (no slash) rule.

Regeneratedpackages/workload-router/src/generated/personas.ts. agentsMdContent is now 25,371 chars and contains all three sections, ready to ship.

Design history

Earlier iterations tried two paths that don't survive cross-repo invocation:

  • Inlining everything in agentsMdContent (one giant escaped string): worked but unmaintainable.
  • Extracting to three local personas/skills/*.md files referenced via local/<name> source paths (the proactive-agents pattern): worked from inside the workforce repo, failed everywhere else. Local skill sources resolve relative paths against process.cwd() at install time; the .md files don't exist in user repos, so cp fails. Reproduced from /tmp/: ✗ 3 of 4 skill(s) failed.

The proactive-agents pattern works because both the persona AND the skill files are co-located in the user's own repo. Persona-maker is a built-in shipped via npm — same pattern doesn't carry.

The agentsMd sidecar approach gets the maintainability win (editable .md file with proper markdown structure) without the cross-repo failure: the generator already inlines the sidecar at build time and the harness loads AGENTS.md from the session cwd, with no runtime filesystem lookups against unfamiliar directories.

Test plan

  • node -e \"require('./personas/persona-maker.json')\" parses; agentsMd resolved to ./persona-maker.md.
  • Catalog generator inlines: published agentsMdContent now 25,371 chars with ## Relayfile mount policy, ## MCP servers, ## Persona sidecar fields.
  • Dry-run from /tmp/ (non-workforce cwd) — the case that previously failed: ✓ dry-run ok: 1 skill(s) installed cleanly.
  • Companion fix in relayfile for the trailing-slash negation walker bug: fix(local-mount): trailing-slash negations now re-include allow-listed directories relayfile#145.

To test locally after merge

The published agentworkforce@3.0.3 on PATH won't pick this up until the next release. To test now:

```bash
cd ~/Projects/AgentWorkforce/workforce
git pull
corepack pnpm install
corepack pnpm --filter @agentworkforce/workload-router --filter @agentworkforce/cli build

From any directory:

node ~/Projects/AgentWorkforce/workforce/packages/cli/dist/cli.js agent persona-maker
```

🤖 Generated with Claude Code

persona-maker.json's AGENTS.md sidecar only listed `mount` and
`mcpServers` as optional fields without explaining when to use them,
the shape, or how harness selection is constrained by MCP support.
Authored personas needing filesystem sandboxing or MCP wiring were a
coin-flip on getting these blocks right.
- Add a `mount` section covering ignoredPatterns/readonlyPatterns
semantics, the `.{persona.id}.agentignore` overlay behavior keyed off
`agentName: persona.id`, the gitignore-negation idiom for allow-lists,
the file-scope-vs-tool-scope split from `permissions`, and the
auto-`.git` sandbox behavior.
- Add an `mcpServers` section with the two spec variants (http/sse vs
stdio), an example of each, `$VAR` substitution policy, and the
claude / codex / opencode support matrix so harness selection is
informed when MCP is required.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR externalizes the persona authoring specification from an inline agentsMdContent field in personas/persona-maker.json into a dedicated personas/persona-maker.md file. The new markdown document provides comprehensive, structured guidance for authoring a Workforce persona, covering required JSON schema, mount policy, MCP servers, sidecar fields, runtime configuration, validation workflow, built-in catalog integration, and explicit anti-goals.

Changes

Persona authoring specification

Layer / File(s)Summary
Persona JSON refactoring and schema foundation
personas/persona-maker.json, personas/persona-maker.md
The JSON file now references ./persona-maker.md instead of embedding agentsMdContent. The new guide introduces required persona JSON shape including id/intent, metadata (tags, description, skills), runtime fields (harness, model, systemPrompt, harnessSettings), and prompt authoring constraints.
Mount policy specification
personas/persona-maker.md, personas/skills/persona-relayfile-mount/SKILL.md
Specifies the mount JSON shape and policy: ignoredPatterns vs readonlyPatterns, per-agent dotfile overlays (.{id}.agentignore/.{id}.agentreadonly), gitignore-style allow-list rules with non-obvious negation requirements, .git sync behavior, and a detailed pre-handoff checklist.
MCP servers specification
personas/persona-maker.md, personas/skills/persona-mcp-servers/SKILL.md
Documents mcpServers configuration including uniform server spec, remote http/sse vs local stdio variants, $VAR/${VAR} secret substitution and unset behavior, harness support matrix, permissions pairing via mcp__* keys, and an MCP authoring checklist.
Sidecar markdown fields specification
personas/persona-maker.md, personas/skills/persona-sidecars/SKILL.md
Defines sidecar fields (claudeMd/agentsMd vs *MdContent), path vs inline semantics and the silent-failure footgun when *MdContent is used incorrectly, *MdMode options (overwrite/extend), and a sidecar authoring checklist.
Runtime, validation, and authoring workflow
personas/persona-maker.md
Lays out runtime defaults for harness, model, reasoning, and timeoutSeconds, describes skill discovery/curation and required agentworkforce agent <id> --dry-run validation checks, details persona prompt authoring steps and built-in catalog integration, lists anti-goals, and specifies the handoff contract.
Skills package manifest, README & LICENSE
personas/skills/prpm.json, personas/skills/README.md, personas/skills/LICENSE
Adds agentworkforce-persona-authoring-skills manifest registering three skills and includes README and MIT license for the skills package.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested reviewers

  • willwashburn

Poem

🐰 The spec hops free from JSON's nest,

A markdown tome emerges dressed,
Mounts and MCPs set in lines,
Sidecars, checklists, clear design,
Persona makers, now you're blessed.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title accurately summarizes the main change: adding guidance documentation for mount/MCP/sidecar features via a persona-maker.md sidecar file referenced in agentsMd.
Description check✅ PassedThe description clearly relates to the changeset, explaining the four failure modes being fixed, the new teaching content added, design decisions, and test plans.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch persona-maker-mount-mcp-guidance

Comment @coderabbitai help to get the list of available commands and usage tips.

@devin-ai-integrationdevin-ai-integrationBot 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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

…ills
The mount and MCP additions from the previous commit made agentsMdContent
even longer. Extract them — plus the silent-footgun guidance about
claudeMdContent vs claudeMd — into three local skill .md files matching
the proactive-agents skill-loading pattern. The skills install into the
session via the local source-kind, so the persona reads them as standalone
SKILL.md files in its working dir instead of carrying everything inline.
Skills:
- personas/skills/relayfile-mount.md — mount field deep dive: allow-list
idiom (/* not **, paired !dir/ + !dir/**), readonlyPatterns scope rule
(never the work dir), agentName overlay, .git sandbox behavior.
- personas/skills/persona-mcp-servers.md — mcpServers two variants
(http/sse vs stdio), $VAR substitution, claude/codex/opencode support
matrix, permissions.allow pairing.
- personas/skills/persona-sidecars.md — claudeMd (path) vs claudeMdContent
(inline) distinction; calls out that the dry-run does NOT catch a path
string mistakenly stored in *MdContent.
persona-maker.json:
- skills[] now declares the three local skills alongside skill.sh/find-skills.
- agentsMdContent trimmed: the long mount/MCP/sidecar paragraphs are
replaced with one-line skill pointers. Net length: 15985 → 15318 chars.
- Anti-goals extended with the four lessons from a recent broken persona:
filename string in *MdContent; ** as broad mount exclude; readonly on
work dir; opencode + mcpServers; bare model alias without version.
- Added 'full model identifiers' rule (claude-sonnet-4-6, not claude-sonnet).
Regenerated packages/workload-router/src/generated/personas.ts to pick up
the new skills.
Dry-run: ✓ 4 skill(s) installed cleanly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgantkhaliqgant changed the title docs(persona-maker): teach mount policy and mcpServers shapefeat(persona-maker): mount/MCP/sidecar guidance as local skillsMay 13, 2026
The "obvious" gitignore allow-list `["/*", "!web/", "!web/**"]` silently
produces an empty mount. Reproduced against relayfile's createMount:
mount root contained only CLAUDE.md, _MOUNT_README.md, and .relayfile-local-mount
— no web/.
Root cause in relayfile-local-mount/src/mount.ts isPathMatched():
return matcher.ignores(relPath) || (isDirectory && matcher.ignores(`${relPath}/`));
The OR short-circuits. For a directory `web`:
- matcher.ignores('web') → true (`/*` matches the bare name)
- matcher.ignores('web/') → false (`!web/` negates the trailing-slash form)
but this branch is never reached.
So `!web/` (slash) only counters the trailing-slash form, leaving the
bare-name check unopposed. The walker treats `web` as ignored and skips
recursion. Verified by harness:
/* + !web/ + !web/** → web (dir) reported as ignored: true (broken)
/* + !web + !web/** → web (dir) reported as ignored: false (correct)
Confirmed end-to-end against a real createMount: with `!web` the mount
root contains web/content/post.md as expected.
Updates:
- relayfile-mount.md skill: add a fourth rule explicitly calling out the
`!dir` vs `!dir/` distinction with the walker's short-circuit as the
reason, plus a "wrong / right" side-by-side. Update the checklist line.
- persona-maker.json anti-goal: replace `!dir/` reference with `!dir`
plus the reason.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitaicoderabbitaiBot 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.

🧹 Nitpick comments (1)
personas/skills/relayfile-mount.md (1)

32-33: 💤 Low value

Consider clarifying the placeholder notation.

The .{id} notation could be more explicit that it's a placeholder. For an AI agent consuming this skill, consider using .${id} or adding a concrete example like "For a persona with id: blog-writer, the dotfile would be .blog-writer.agentignore."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@personas/skills/relayfile-mount.md` around lines 32 - 33, The placeholder
notation `.{id}.agentignore` and `.{id}.agentreadonly` is ambiguous; update
these entries to use a clearer placeholder like `.${id}.agentignore` and
`.${id}.agentreadonly` or add a concrete example line (e.g., for `id:
blog-writer` show `.blog-writer.agentignore`) so readers and agents understand
that `{id}` is substituted with the persona id.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@personas/skills/relayfile-mount.md`:
- Around line 32-33: The placeholder notation `.{id}.agentignore` and
`.{id}.agentreadonly` is ambiguous; update these entries to use a clearer
placeholder like `.${id}.agentignore` and `.${id}.agentreadonly` or add a
concrete example line (e.g., for `id: blog-writer` show
`.blog-writer.agentignore`) so readers and agents understand that `{id}` is
substituted with the persona id.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 51803e8c-d30a-4235-a2b0-74028ad47bff

📥 Commits

Reviewing files that changed from the base of the PR and between dc4ec59 and bfe36f5.

⛔ Files ignored due to path filters (1)
  • packages/workload-router/src/generated/personas.ts is excluded by !**/generated/**
📒 Files selected for processing (4)
  • personas/persona-maker.json
  • personas/skills/persona-mcp-servers.md
  • personas/skills/persona-sidecars.md
  • personas/skills/relayfile-mount.md
✅ Files skipped from review due to trivial changes (2)
  • personas/skills/persona-sidecars.md
  • personas/skills/persona-mcp-servers.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • personas/persona-maker.json

The previous extraction-into-local-skills approach was broken in the
field. Reported live: persona-maker spawned from a non-workforce cwd
(e.g. ../relay) only loaded `find-skills` — the three local skills
`relayfile-mount`, `persona-mcp-servers`, `persona-sidecars` were
missing from opencode's Skills picker.
Two layered bugs:
1. The agentworkforce binary on PATH is the published 3.0.3 from npm.
Its baked-in catalog has the old persona-maker (only find-skills).
New skills aren't visible until a release lands.
2. Even with the local CLI build, local skill sources resolve relative
paths against process.cwd() at install time. When invoked from
`/tmp/` or any non-workforce repo, `cp personas/skills/<x>.md ...`
fails because the .md files only exist in the workforce source repo.
Three of four skill installs fail with exit code 1.
The proactive-agents pattern (local/<name> source paths) works there
because both the persona AND its skill .md files are co-located in
the same user-repo. Persona-maker is a BUILT-IN shipped via npm —
that pattern doesn't carry across.
Fix: use the agentsMd path-form sidecar. The catalog generator at
`packages/workload-router/scripts/generate-personas.mjs` already
inlines sidecar .md content into agentsMdContent at build time, so
the published package ships a single bundled spec. The .md file is a
real markdown file the author can edit ergonomically; the user sees
the full content in AGENTS.md at session start with no runtime
filesystem lookups required.
Changes:
- New: personas/persona-maker.md — full operating spec including the
Relayfile mount, MCP servers, and Persona sidecar sections that were
previously split into local skill files. Same content the generator
would have inlined; consolidated into one file because cross-cwd
resolution made splitting unworkable.
- personas/persona-maker.json: replace agentsMdContent (inline) with
agentsMd (./persona-maker.md). Drop the three local/ skill entries
from skills[]; only skill.sh/find-skills remains.
- Delete personas/skills/* — content lives in persona-maker.md now.
- Regenerated packages/workload-router/src/generated/personas.ts;
agentsMdContent now 25,371 chars with all three sections inlined.
Verified: dry-run green from /tmp (non-workforce cwd) — the
cross-repo case that previously produced 3 of 4 failed installs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgantkhaliqgant changed the title feat(persona-maker): mount/MCP/sidecar guidance as local skillsfeat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecarMay 13, 2026
Ricky Schema Cascadeand others added 4 commits May 13, 2026 14:04
…m.dev
Previous iterations tried inlining everything in agentsMdContent and then
extracting to local skill .md files referenced via repo-relative paths.
The local-path approach broke cross-repo invocation because local skill
sources resolve against process.cwd() at install time, not the workforce
package install root. Confirmed live: persona-maker spawned from
/Users/khaliqgant/Projects/AgentWorkforce/relay only saw skill.sh/find-skills
in the opencode picker.
Fix: publish the three skills as prpm packages so they're installable from
any cwd via npx -y prpm install <ref>.
Package layout (personas/skills/):
- prpm.json — multi-package manifest following the
@prpm/prpm-json-best-practices-skill structure: top-level metadata
(name, version, author, license, repository, organization), plus a
packages[] with three skill entries (format: generic, subtype: skill).
- LICENSE — MIT, picked up automatically by prpm publish for all packages.
- README.md — discovery / install docs.
- persona-relayfile-mount/SKILL.md — mount field deep dive: allow-list
idiom, !web vs !web/ walker gotcha, readonlyPatterns scope, agentName
overlay, .git sandbox.
- persona-mcp-servers/SKILL.md — mcpServers spec variants, $VAR
substitution, claude/codex/opencode harness matrix, permissions.allow
pairing.
- persona-sidecars/SKILL.md — claudeMd (path) vs claudeMdContent (inline)
distinction; the silent footgun the dry-run does NOT catch.
persona-maker.json:
- skills[] now declares the three @agent-workforce/persona-* refs
alongside skill.sh/find-skills. They install via prpm at session start
and appear in the opencode Skills picker.
- agentsMd: ./persona-maker.md — slim sidecar restored, with the three
embedded sections replaced by pointers to the published skills.
Anti-goals updated to reference the new skill IDs.
Regenerated packages/workload-router/src/generated/personas.ts.
`prpm publish --dry-run` from personas/skills/: ✓ all 3 packages ready
to publish under @agent-workforce/ scope (khaliqgant ✓ as org member).
Publish runs separately (user-driven, not automated in this commit).
After publish lands on prpm.dev, `agentworkforce agent persona-maker
--dry-run` will install all four skills cleanly. Until then the dry-run
exercising the three new skills will fail at the prpm registry lookup
step — expected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…works
Published 1.0.0 with format: generic. Install via `npx -y prpm install
@agent-workforce/persona-relayfile-mount --as opencode` (the command
persona-kit emits for opencode-harness personas) errors with:
Failed to parse generic format: Unsupported source format for
conversion: generic
prpm has format converters keyed off the source format. `generic` has
no converter to `opencode` / `codex` / etc., so install fails the
moment the workforce CLI tries to materialize the skill.
Bump to 1.0.1 with format: claude. SKILL.md with YAML frontmatter is
canonically claude-flavored, and prpm knows how to convert claude →
opencode (verified by installing @agent-relay/choosing-swarm-patterns
with --as opencode: ✓ Converted from claude to opencode).
Dry-run validates clean for all three packages at 1.0.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…eneric
Verified after publish: `prpm show @agent-workforce/persona-relayfile-mount`
returns "Type: generic skill" at version 1.0.1, and `prpm install --as
opencode` still errors "Failed to parse generic format". Either the
publish of 1.0.1 happened before the format-change commit landed in the
working tree, or prpm caches format metadata at first publish — either
way, the remote tarball is still generic.
Bump to 1.0.2 with format: claude. Dry-run confirms:
Package: @agent-workforce/persona-relayfile-mount@1.0.2
Format: claude | Subtype: skill
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The prpm registry route now updates mutable manifest fields on republish
(format, subtype, description, tags, etc.), so the three skills finally
landed as format: claude. Verified end-to-end:
- `prpm show @agent-workforce/persona-relayfile-mount` reports Type:
claude skill at v1.0.3 (previously locked at generic from 1.0.0).
- `agentworkforce agent persona-maker --dry-run` from /tmp:
✓ dry-run ok: 4 skill(s) installed cleanly. All three new skills now
convert claude → opencode and materialize into .opencode/skills/ at
session start.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
khaliqgant merged commit a338122 into mainMay 13, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the persona-maker-mount-mcp-guidance branch May 13, 2026 12:55
Sign up for freeto 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.

1 participant

@khaliqgant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecar - #108

Merged
khaliqgant merged 8 commits into
mainfrom
persona-maker-mount-mcp-guidance
May 13, 2026
Merged

feat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecar#108
khaliqgant merged 8 commits into
mainfrom
persona-maker-mount-mcp-guidance

Conversation

@khaliqgant

@khaliqgantkhaliqgant commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

The persona-maker built-in was missing teaching content for mount, mcpServers, and the silent-footgun distinction between claudeMd (path) and claudeMdContent (inline). A persona authored against the existing spec hit four real failure modes:

  1. claudeMdContent: \"web-blog-content-writer.claudeMdContent.md\" — filename string written verbatim as CLAUDE.md body (dry-run green, agent boots with no spec).
  2. mount.ignoredPatterns: [\"**\", \"!./web/**\"]** breaks ! re-includes; empty mount.
  3. readonlyPatterns: [\"web/**\"] on the persona's own work directory — writes silently dropped on sync-back.
  4. model: \"claude-sonnet\" — bare alias without version, harness errors at spawn.

Changes

New filepersonas/persona-maker.md — the persona's full operating spec, including dedicated sections for Relayfile mount policy (allow-list idiom, the non-obvious !web vs !web/ walker bug, readonlyPatterns scope rule, per-agent dotfile overlay, .git sandbox behavior), MCP servers (two spec variants, \$VAR secret substitution, claude/codex/opencode support matrix, permissions.allow pairing), and Persona sidecar fields (path-vs-inline distinction with explicit "dry-run does NOT catch this" callout).

persona-maker.json:

  • Replaces inline agentsMdContent with agentsMd: \"./persona-maker.md\" (path form). The catalog generator at packages/workload-router/scripts/generate-personas.mjs inlines the .md content into the published spec at build time, so the package still ships a single bundled JSON.
  • New rules in the body: full model identifiers (claude-sonnet-4-6 not claude-sonnet).
  • Anti-goals extended with the four lessons learned plus the mount allow-list !dir (no slash) rule.

Regeneratedpackages/workload-router/src/generated/personas.ts. agentsMdContent is now 25,371 chars and contains all three sections, ready to ship.

Design history

Earlier iterations tried two paths that don't survive cross-repo invocation:

  • Inlining everything in agentsMdContent (one giant escaped string): worked but unmaintainable.
  • Extracting to three local personas/skills/*.md files referenced via local/<name> source paths (the proactive-agents pattern): worked from inside the workforce repo, failed everywhere else. Local skill sources resolve relative paths against process.cwd() at install time; the .md files don't exist in user repos, so cp fails. Reproduced from /tmp/: ✗ 3 of 4 skill(s) failed.

The proactive-agents pattern works because both the persona AND the skill files are co-located in the user's own repo. Persona-maker is a built-in shipped via npm — same pattern doesn't carry.

The agentsMd sidecar approach gets the maintainability win (editable .md file with proper markdown structure) without the cross-repo failure: the generator already inlines the sidecar at build time and the harness loads AGENTS.md from the session cwd, with no runtime filesystem lookups against unfamiliar directories.

Test plan

  • node -e \"require('./personas/persona-maker.json')\" parses; agentsMd resolved to ./persona-maker.md.
  • Catalog generator inlines: published agentsMdContent now 25,371 chars with ## Relayfile mount policy, ## MCP servers, ## Persona sidecar fields.
  • Dry-run from /tmp/ (non-workforce cwd) — the case that previously failed: ✓ dry-run ok: 1 skill(s) installed cleanly.
  • Companion fix in relayfile for the trailing-slash negation walker bug: fix(local-mount): trailing-slash negations now re-include allow-listed directories relayfile#145.

To test locally after merge

The published agentworkforce@3.0.3 on PATH won't pick this up until the next release. To test now:

```bash
cd ~/Projects/AgentWorkforce/workforce
git pull
corepack pnpm install
corepack pnpm --filter @agentworkforce/workload-router --filter @agentworkforce/cli build

From any directory:

node ~/Projects/AgentWorkforce/workforce/packages/cli/dist/cli.js agent persona-maker
```

🤖 Generated with Claude Code

persona-maker.json's AGENTS.md sidecar only listed `mount` and
`mcpServers` as optional fields without explaining when to use them,
the shape, or how harness selection is constrained by MCP support.
Authored personas needing filesystem sandboxing or MCP wiring were a
coin-flip on getting these blocks right.
- Add a `mount` section covering ignoredPatterns/readonlyPatterns
semantics, the `.{persona.id}.agentignore` overlay behavior keyed off
`agentName: persona.id`, the gitignore-negation idiom for allow-lists,
the file-scope-vs-tool-scope split from `permissions`, and the
auto-`.git` sandbox behavior.
- Add an `mcpServers` section with the two spec variants (http/sse vs
stdio), an example of each, `$VAR` substitution policy, and the
claude / codex / opencode support matrix so harness selection is
informed when MCP is required.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR externalizes the persona authoring specification from an inline agentsMdContent field in personas/persona-maker.json into a dedicated personas/persona-maker.md file. The new markdown document provides comprehensive, structured guidance for authoring a Workforce persona, covering required JSON schema, mount policy, MCP servers, sidecar fields, runtime configuration, validation workflow, built-in catalog integration, and explicit anti-goals.

Changes

Persona authoring specification

Layer / File(s)Summary
Persona JSON refactoring and schema foundation
personas/persona-maker.json, personas/persona-maker.md
The JSON file now references ./persona-maker.md instead of embedding agentsMdContent. The new guide introduces required persona JSON shape including id/intent, metadata (tags, description, skills), runtime fields (harness, model, systemPrompt, harnessSettings), and prompt authoring constraints.
Mount policy specification
personas/persona-maker.md, personas/skills/persona-relayfile-mount/SKILL.md
Specifies the mount JSON shape and policy: ignoredPatterns vs readonlyPatterns, per-agent dotfile overlays (.{id}.agentignore/.{id}.agentreadonly), gitignore-style allow-list rules with non-obvious negation requirements, .git sync behavior, and a detailed pre-handoff checklist.
MCP servers specification
personas/persona-maker.md, personas/skills/persona-mcp-servers/SKILL.md
Documents mcpServers configuration including uniform server spec, remote http/sse vs local stdio variants, $VAR/${VAR} secret substitution and unset behavior, harness support matrix, permissions pairing via mcp__* keys, and an MCP authoring checklist.
Sidecar markdown fields specification
personas/persona-maker.md, personas/skills/persona-sidecars/SKILL.md
Defines sidecar fields (claudeMd/agentsMd vs *MdContent), path vs inline semantics and the silent-failure footgun when *MdContent is used incorrectly, *MdMode options (overwrite/extend), and a sidecar authoring checklist.
Runtime, validation, and authoring workflow
personas/persona-maker.md
Lays out runtime defaults for harness, model, reasoning, and timeoutSeconds, describes skill discovery/curation and required agentworkforce agent <id> --dry-run validation checks, details persona prompt authoring steps and built-in catalog integration, lists anti-goals, and specifies the handoff contract.
Skills package manifest, README & LICENSE
personas/skills/prpm.json, personas/skills/README.md, personas/skills/LICENSE
Adds agentworkforce-persona-authoring-skills manifest registering three skills and includes README and MIT license for the skills package.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested reviewers

  • willwashburn

Poem

🐰 The spec hops free from JSON's nest,

A markdown tome emerges dressed,
Mounts and MCPs set in lines,
Sidecars, checklists, clear design,
Persona makers, now you're blessed.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title accurately summarizes the main change: adding guidance documentation for mount/MCP/sidecar features via a persona-maker.md sidecar file referenced in agentsMd.
Description check✅ PassedThe description clearly relates to the changeset, explaining the four failure modes being fixed, the new teaching content added, design decisions, and test plans.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch persona-maker-mount-mcp-guidance

Comment @coderabbitai help to get the list of available commands and usage tips.

@devin-ai-integrationdevin-ai-integrationBot 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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

…ills
The mount and MCP additions from the previous commit made agentsMdContent
even longer. Extract them — plus the silent-footgun guidance about
claudeMdContent vs claudeMd — into three local skill .md files matching
the proactive-agents skill-loading pattern. The skills install into the
session via the local source-kind, so the persona reads them as standalone
SKILL.md files in its working dir instead of carrying everything inline.
Skills:
- personas/skills/relayfile-mount.md — mount field deep dive: allow-list
idiom (/* not **, paired !dir/ + !dir/**), readonlyPatterns scope rule
(never the work dir), agentName overlay, .git sandbox behavior.
- personas/skills/persona-mcp-servers.md — mcpServers two variants
(http/sse vs stdio), $VAR substitution, claude/codex/opencode support
matrix, permissions.allow pairing.
- personas/skills/persona-sidecars.md — claudeMd (path) vs claudeMdContent
(inline) distinction; calls out that the dry-run does NOT catch a path
string mistakenly stored in *MdContent.
persona-maker.json:
- skills[] now declares the three local skills alongside skill.sh/find-skills.
- agentsMdContent trimmed: the long mount/MCP/sidecar paragraphs are
replaced with one-line skill pointers. Net length: 15985 → 15318 chars.
- Anti-goals extended with the four lessons from a recent broken persona:
filename string in *MdContent; ** as broad mount exclude; readonly on
work dir; opencode + mcpServers; bare model alias without version.
- Added 'full model identifiers' rule (claude-sonnet-4-6, not claude-sonnet).
Regenerated packages/workload-router/src/generated/personas.ts to pick up
the new skills.
Dry-run: ✓ 4 skill(s) installed cleanly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgantkhaliqgant changed the title docs(persona-maker): teach mount policy and mcpServers shapefeat(persona-maker): mount/MCP/sidecar guidance as local skillsMay 13, 2026
The "obvious" gitignore allow-list `["/*", "!web/", "!web/**"]` silently
produces an empty mount. Reproduced against relayfile's createMount:
mount root contained only CLAUDE.md, _MOUNT_README.md, and .relayfile-local-mount
— no web/.
Root cause in relayfile-local-mount/src/mount.ts isPathMatched():
return matcher.ignores(relPath) || (isDirectory && matcher.ignores(`${relPath}/`));
The OR short-circuits. For a directory `web`:
- matcher.ignores('web') → true (`/*` matches the bare name)
- matcher.ignores('web/') → false (`!web/` negates the trailing-slash form)
but this branch is never reached.
So `!web/` (slash) only counters the trailing-slash form, leaving the
bare-name check unopposed. The walker treats `web` as ignored and skips
recursion. Verified by harness:
/* + !web/ + !web/** → web (dir) reported as ignored: true (broken)
/* + !web + !web/** → web (dir) reported as ignored: false (correct)
Confirmed end-to-end against a real createMount: with `!web` the mount
root contains web/content/post.md as expected.
Updates:
- relayfile-mount.md skill: add a fourth rule explicitly calling out the
`!dir` vs `!dir/` distinction with the walker's short-circuit as the
reason, plus a "wrong / right" side-by-side. Update the checklist line.
- persona-maker.json anti-goal: replace `!dir/` reference with `!dir`
plus the reason.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitaicoderabbitaiBot 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.

🧹 Nitpick comments (1)
personas/skills/relayfile-mount.md (1)

32-33: 💤 Low value

Consider clarifying the placeholder notation.

The .{id} notation could be more explicit that it's a placeholder. For an AI agent consuming this skill, consider using .${id} or adding a concrete example like "For a persona with id: blog-writer, the dotfile would be .blog-writer.agentignore."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@personas/skills/relayfile-mount.md` around lines 32 - 33, The placeholder
notation `.{id}.agentignore` and `.{id}.agentreadonly` is ambiguous; update
these entries to use a clearer placeholder like `.${id}.agentignore` and
`.${id}.agentreadonly` or add a concrete example line (e.g., for `id:
blog-writer` show `.blog-writer.agentignore`) so readers and agents understand
that `{id}` is substituted with the persona id.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@personas/skills/relayfile-mount.md`:
- Around line 32-33: The placeholder notation `.{id}.agentignore` and
`.{id}.agentreadonly` is ambiguous; update these entries to use a clearer
placeholder like `.${id}.agentignore` and `.${id}.agentreadonly` or add a
concrete example line (e.g., for `id: blog-writer` show
`.blog-writer.agentignore`) so readers and agents understand that `{id}` is
substituted with the persona id.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 51803e8c-d30a-4235-a2b0-74028ad47bff

📥 Commits

Reviewing files that changed from the base of the PR and between dc4ec59 and bfe36f5.

⛔ Files ignored due to path filters (1)
  • packages/workload-router/src/generated/personas.ts is excluded by !**/generated/**
📒 Files selected for processing (4)
  • personas/persona-maker.json
  • personas/skills/persona-mcp-servers.md
  • personas/skills/persona-sidecars.md
  • personas/skills/relayfile-mount.md
✅ Files skipped from review due to trivial changes (2)
  • personas/skills/persona-sidecars.md
  • personas/skills/persona-mcp-servers.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • personas/persona-maker.json

The previous extraction-into-local-skills approach was broken in the
field. Reported live: persona-maker spawned from a non-workforce cwd
(e.g. ../relay) only loaded `find-skills` — the three local skills
`relayfile-mount`, `persona-mcp-servers`, `persona-sidecars` were
missing from opencode's Skills picker.
Two layered bugs:
1. The agentworkforce binary on PATH is the published 3.0.3 from npm.
Its baked-in catalog has the old persona-maker (only find-skills).
New skills aren't visible until a release lands.
2. Even with the local CLI build, local skill sources resolve relative
paths against process.cwd() at install time. When invoked from
`/tmp/` or any non-workforce repo, `cp personas/skills/<x>.md ...`
fails because the .md files only exist in the workforce source repo.
Three of four skill installs fail with exit code 1.
The proactive-agents pattern (local/<name> source paths) works there
because both the persona AND its skill .md files are co-located in
the same user-repo. Persona-maker is a BUILT-IN shipped via npm —
that pattern doesn't carry across.
Fix: use the agentsMd path-form sidecar. The catalog generator at
`packages/workload-router/scripts/generate-personas.mjs` already
inlines sidecar .md content into agentsMdContent at build time, so
the published package ships a single bundled spec. The .md file is a
real markdown file the author can edit ergonomically; the user sees
the full content in AGENTS.md at session start with no runtime
filesystem lookups required.
Changes:
- New: personas/persona-maker.md — full operating spec including the
Relayfile mount, MCP servers, and Persona sidecar sections that were
previously split into local skill files. Same content the generator
would have inlined; consolidated into one file because cross-cwd
resolution made splitting unworkable.
- personas/persona-maker.json: replace agentsMdContent (inline) with
agentsMd (./persona-maker.md). Drop the three local/ skill entries
from skills[]; only skill.sh/find-skills remains.
- Delete personas/skills/* — content lives in persona-maker.md now.
- Regenerated packages/workload-router/src/generated/personas.ts;
agentsMdContent now 25,371 chars with all three sections inlined.
Verified: dry-run green from /tmp (non-workforce cwd) — the
cross-repo case that previously produced 3 of 4 failed installs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgantkhaliqgant changed the title feat(persona-maker): mount/MCP/sidecar guidance as local skillsfeat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecarMay 13, 2026
Ricky Schema Cascadeand others added 4 commits May 13, 2026 14:04
…m.dev
Previous iterations tried inlining everything in agentsMdContent and then
extracting to local skill .md files referenced via repo-relative paths.
The local-path approach broke cross-repo invocation because local skill
sources resolve against process.cwd() at install time, not the workforce
package install root. Confirmed live: persona-maker spawned from
/Users/khaliqgant/Projects/AgentWorkforce/relay only saw skill.sh/find-skills
in the opencode picker.
Fix: publish the three skills as prpm packages so they're installable from
any cwd via npx -y prpm install <ref>.
Package layout (personas/skills/):
- prpm.json — multi-package manifest following the
@prpm/prpm-json-best-practices-skill structure: top-level metadata
(name, version, author, license, repository, organization), plus a
packages[] with three skill entries (format: generic, subtype: skill).
- LICENSE — MIT, picked up automatically by prpm publish for all packages.
- README.md — discovery / install docs.
- persona-relayfile-mount/SKILL.md — mount field deep dive: allow-list
idiom, !web vs !web/ walker gotcha, readonlyPatterns scope, agentName
overlay, .git sandbox.
- persona-mcp-servers/SKILL.md — mcpServers spec variants, $VAR
substitution, claude/codex/opencode harness matrix, permissions.allow
pairing.
- persona-sidecars/SKILL.md — claudeMd (path) vs claudeMdContent (inline)
distinction; the silent footgun the dry-run does NOT catch.
persona-maker.json:
- skills[] now declares the three @agent-workforce/persona-* refs
alongside skill.sh/find-skills. They install via prpm at session start
and appear in the opencode Skills picker.
- agentsMd: ./persona-maker.md — slim sidecar restored, with the three
embedded sections replaced by pointers to the published skills.
Anti-goals updated to reference the new skill IDs.
Regenerated packages/workload-router/src/generated/personas.ts.
`prpm publish --dry-run` from personas/skills/: ✓ all 3 packages ready
to publish under @agent-workforce/ scope (khaliqgant ✓ as org member).
Publish runs separately (user-driven, not automated in this commit).
After publish lands on prpm.dev, `agentworkforce agent persona-maker
--dry-run` will install all four skills cleanly. Until then the dry-run
exercising the three new skills will fail at the prpm registry lookup
step — expected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…works
Published 1.0.0 with format: generic. Install via `npx -y prpm install
@agent-workforce/persona-relayfile-mount --as opencode` (the command
persona-kit emits for opencode-harness personas) errors with:
Failed to parse generic format: Unsupported source format for
conversion: generic
prpm has format converters keyed off the source format. `generic` has
no converter to `opencode` / `codex` / etc., so install fails the
moment the workforce CLI tries to materialize the skill.
Bump to 1.0.1 with format: claude. SKILL.md with YAML frontmatter is
canonically claude-flavored, and prpm knows how to convert claude →
opencode (verified by installing @agent-relay/choosing-swarm-patterns
with --as opencode: ✓ Converted from claude to opencode).
Dry-run validates clean for all three packages at 1.0.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…eneric
Verified after publish: `prpm show @agent-workforce/persona-relayfile-mount`
returns "Type: generic skill" at version 1.0.1, and `prpm install --as
opencode` still errors "Failed to parse generic format". Either the
publish of 1.0.1 happened before the format-change commit landed in the
working tree, or prpm caches format metadata at first publish — either
way, the remote tarball is still generic.
Bump to 1.0.2 with format: claude. Dry-run confirms:
Package: @agent-workforce/persona-relayfile-mount@1.0.2
Format: claude | Subtype: skill
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The prpm registry route now updates mutable manifest fields on republish
(format, subtype, description, tags, etc.), so the three skills finally
landed as format: claude. Verified end-to-end:
- `prpm show @agent-workforce/persona-relayfile-mount` reports Type:
claude skill at v1.0.3 (previously locked at generic from 1.0.0).
- `agentworkforce agent persona-maker --dry-run` from /tmp:
✓ dry-run ok: 4 skill(s) installed cleanly. All three new skills now
convert claude → opencode and materialize into .opencode/skills/ at
session start.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
khaliqgant merged commit a338122 into mainMay 13, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the persona-maker-mount-mcp-guidance branch May 13, 2026 12:55
Sign up for freeto 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.

1 participant

@khaliqgant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecar - #108

Merged
khaliqgant merged 8 commits into
mainfrom
persona-maker-mount-mcp-guidance
May 13, 2026
Merged

feat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecar#108
khaliqgant merged 8 commits into
mainfrom
persona-maker-mount-mcp-guidance

Conversation

@khaliqgant

@khaliqgantkhaliqgant commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

The persona-maker built-in was missing teaching content for mount, mcpServers, and the silent-footgun distinction between claudeMd (path) and claudeMdContent (inline). A persona authored against the existing spec hit four real failure modes:

  1. claudeMdContent: \"web-blog-content-writer.claudeMdContent.md\" — filename string written verbatim as CLAUDE.md body (dry-run green, agent boots with no spec).
  2. mount.ignoredPatterns: [\"**\", \"!./web/**\"]** breaks ! re-includes; empty mount.
  3. readonlyPatterns: [\"web/**\"] on the persona's own work directory — writes silently dropped on sync-back.
  4. model: \"claude-sonnet\" — bare alias without version, harness errors at spawn.

Changes

New filepersonas/persona-maker.md — the persona's full operating spec, including dedicated sections for Relayfile mount policy (allow-list idiom, the non-obvious !web vs !web/ walker bug, readonlyPatterns scope rule, per-agent dotfile overlay, .git sandbox behavior), MCP servers (two spec variants, \$VAR secret substitution, claude/codex/opencode support matrix, permissions.allow pairing), and Persona sidecar fields (path-vs-inline distinction with explicit "dry-run does NOT catch this" callout).

persona-maker.json:

  • Replaces inline agentsMdContent with agentsMd: \"./persona-maker.md\" (path form). The catalog generator at packages/workload-router/scripts/generate-personas.mjs inlines the .md content into the published spec at build time, so the package still ships a single bundled JSON.
  • New rules in the body: full model identifiers (claude-sonnet-4-6 not claude-sonnet).
  • Anti-goals extended with the four lessons learned plus the mount allow-list !dir (no slash) rule.

Regeneratedpackages/workload-router/src/generated/personas.ts. agentsMdContent is now 25,371 chars and contains all three sections, ready to ship.

Design history

Earlier iterations tried two paths that don't survive cross-repo invocation:

  • Inlining everything in agentsMdContent (one giant escaped string): worked but unmaintainable.
  • Extracting to three local personas/skills/*.md files referenced via local/<name> source paths (the proactive-agents pattern): worked from inside the workforce repo, failed everywhere else. Local skill sources resolve relative paths against process.cwd() at install time; the .md files don't exist in user repos, so cp fails. Reproduced from /tmp/: ✗ 3 of 4 skill(s) failed.

The proactive-agents pattern works because both the persona AND the skill files are co-located in the user's own repo. Persona-maker is a built-in shipped via npm — same pattern doesn't carry.

The agentsMd sidecar approach gets the maintainability win (editable .md file with proper markdown structure) without the cross-repo failure: the generator already inlines the sidecar at build time and the harness loads AGENTS.md from the session cwd, with no runtime filesystem lookups against unfamiliar directories.

Test plan

  • node -e \"require('./personas/persona-maker.json')\" parses; agentsMd resolved to ./persona-maker.md.
  • Catalog generator inlines: published agentsMdContent now 25,371 chars with ## Relayfile mount policy, ## MCP servers, ## Persona sidecar fields.
  • Dry-run from /tmp/ (non-workforce cwd) — the case that previously failed: ✓ dry-run ok: 1 skill(s) installed cleanly.
  • Companion fix in relayfile for the trailing-slash negation walker bug: fix(local-mount): trailing-slash negations now re-include allow-listed directories relayfile#145.

To test locally after merge

The published agentworkforce@3.0.3 on PATH won't pick this up until the next release. To test now:

```bash
cd ~/Projects/AgentWorkforce/workforce
git pull
corepack pnpm install
corepack pnpm --filter @agentworkforce/workload-router --filter @agentworkforce/cli build

From any directory:

node ~/Projects/AgentWorkforce/workforce/packages/cli/dist/cli.js agent persona-maker
```

🤖 Generated with Claude Code

persona-maker.json's AGENTS.md sidecar only listed `mount` and
`mcpServers` as optional fields without explaining when to use them,
the shape, or how harness selection is constrained by MCP support.
Authored personas needing filesystem sandboxing or MCP wiring were a
coin-flip on getting these blocks right.
- Add a `mount` section covering ignoredPatterns/readonlyPatterns
semantics, the `.{persona.id}.agentignore` overlay behavior keyed off
`agentName: persona.id`, the gitignore-negation idiom for allow-lists,
the file-scope-vs-tool-scope split from `permissions`, and the
auto-`.git` sandbox behavior.
- Add an `mcpServers` section with the two spec variants (http/sse vs
stdio), an example of each, `$VAR` substitution policy, and the
claude / codex / opencode support matrix so harness selection is
informed when MCP is required.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR externalizes the persona authoring specification from an inline agentsMdContent field in personas/persona-maker.json into a dedicated personas/persona-maker.md file. The new markdown document provides comprehensive, structured guidance for authoring a Workforce persona, covering required JSON schema, mount policy, MCP servers, sidecar fields, runtime configuration, validation workflow, built-in catalog integration, and explicit anti-goals.

Changes

Persona authoring specification

Layer / File(s)Summary
Persona JSON refactoring and schema foundation
personas/persona-maker.json, personas/persona-maker.md
The JSON file now references ./persona-maker.md instead of embedding agentsMdContent. The new guide introduces required persona JSON shape including id/intent, metadata (tags, description, skills), runtime fields (harness, model, systemPrompt, harnessSettings), and prompt authoring constraints.
Mount policy specification
personas/persona-maker.md, personas/skills/persona-relayfile-mount/SKILL.md
Specifies the mount JSON shape and policy: ignoredPatterns vs readonlyPatterns, per-agent dotfile overlays (.{id}.agentignore/.{id}.agentreadonly), gitignore-style allow-list rules with non-obvious negation requirements, .git sync behavior, and a detailed pre-handoff checklist.
MCP servers specification
personas/persona-maker.md, personas/skills/persona-mcp-servers/SKILL.md
Documents mcpServers configuration including uniform server spec, remote http/sse vs local stdio variants, $VAR/${VAR} secret substitution and unset behavior, harness support matrix, permissions pairing via mcp__* keys, and an MCP authoring checklist.
Sidecar markdown fields specification
personas/persona-maker.md, personas/skills/persona-sidecars/SKILL.md
Defines sidecar fields (claudeMd/agentsMd vs *MdContent), path vs inline semantics and the silent-failure footgun when *MdContent is used incorrectly, *MdMode options (overwrite/extend), and a sidecar authoring checklist.
Runtime, validation, and authoring workflow
personas/persona-maker.md
Lays out runtime defaults for harness, model, reasoning, and timeoutSeconds, describes skill discovery/curation and required agentworkforce agent <id> --dry-run validation checks, details persona prompt authoring steps and built-in catalog integration, lists anti-goals, and specifies the handoff contract.
Skills package manifest, README & LICENSE
personas/skills/prpm.json, personas/skills/README.md, personas/skills/LICENSE
Adds agentworkforce-persona-authoring-skills manifest registering three skills and includes README and MIT license for the skills package.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested reviewers

  • willwashburn

Poem

🐰 The spec hops free from JSON's nest,

A markdown tome emerges dressed,
Mounts and MCPs set in lines,
Sidecars, checklists, clear design,
Persona makers, now you're blessed.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title accurately summarizes the main change: adding guidance documentation for mount/MCP/sidecar features via a persona-maker.md sidecar file referenced in agentsMd.
Description check✅ PassedThe description clearly relates to the changeset, explaining the four failure modes being fixed, the new teaching content added, design decisions, and test plans.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch persona-maker-mount-mcp-guidance

Comment @coderabbitai help to get the list of available commands and usage tips.

@devin-ai-integrationdevin-ai-integrationBot 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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

…ills
The mount and MCP additions from the previous commit made agentsMdContent
even longer. Extract them — plus the silent-footgun guidance about
claudeMdContent vs claudeMd — into three local skill .md files matching
the proactive-agents skill-loading pattern. The skills install into the
session via the local source-kind, so the persona reads them as standalone
SKILL.md files in its working dir instead of carrying everything inline.
Skills:
- personas/skills/relayfile-mount.md — mount field deep dive: allow-list
idiom (/* not **, paired !dir/ + !dir/**), readonlyPatterns scope rule
(never the work dir), agentName overlay, .git sandbox behavior.
- personas/skills/persona-mcp-servers.md — mcpServers two variants
(http/sse vs stdio), $VAR substitution, claude/codex/opencode support
matrix, permissions.allow pairing.
- personas/skills/persona-sidecars.md — claudeMd (path) vs claudeMdContent
(inline) distinction; calls out that the dry-run does NOT catch a path
string mistakenly stored in *MdContent.
persona-maker.json:
- skills[] now declares the three local skills alongside skill.sh/find-skills.
- agentsMdContent trimmed: the long mount/MCP/sidecar paragraphs are
replaced with one-line skill pointers. Net length: 15985 → 15318 chars.
- Anti-goals extended with the four lessons from a recent broken persona:
filename string in *MdContent; ** as broad mount exclude; readonly on
work dir; opencode + mcpServers; bare model alias without version.
- Added 'full model identifiers' rule (claude-sonnet-4-6, not claude-sonnet).
Regenerated packages/workload-router/src/generated/personas.ts to pick up
the new skills.
Dry-run: ✓ 4 skill(s) installed cleanly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgantkhaliqgant changed the title docs(persona-maker): teach mount policy and mcpServers shapefeat(persona-maker): mount/MCP/sidecar guidance as local skillsMay 13, 2026
The "obvious" gitignore allow-list `["/*", "!web/", "!web/**"]` silently
produces an empty mount. Reproduced against relayfile's createMount:
mount root contained only CLAUDE.md, _MOUNT_README.md, and .relayfile-local-mount
— no web/.
Root cause in relayfile-local-mount/src/mount.ts isPathMatched():
return matcher.ignores(relPath) || (isDirectory && matcher.ignores(`${relPath}/`));
The OR short-circuits. For a directory `web`:
- matcher.ignores('web') → true (`/*` matches the bare name)
- matcher.ignores('web/') → false (`!web/` negates the trailing-slash form)
but this branch is never reached.
So `!web/` (slash) only counters the trailing-slash form, leaving the
bare-name check unopposed. The walker treats `web` as ignored and skips
recursion. Verified by harness:
/* + !web/ + !web/** → web (dir) reported as ignored: true (broken)
/* + !web + !web/** → web (dir) reported as ignored: false (correct)
Confirmed end-to-end against a real createMount: with `!web` the mount
root contains web/content/post.md as expected.
Updates:
- relayfile-mount.md skill: add a fourth rule explicitly calling out the
`!dir` vs `!dir/` distinction with the walker's short-circuit as the
reason, plus a "wrong / right" side-by-side. Update the checklist line.
- persona-maker.json anti-goal: replace `!dir/` reference with `!dir`
plus the reason.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitaicoderabbitaiBot 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.

🧹 Nitpick comments (1)
personas/skills/relayfile-mount.md (1)

32-33: 💤 Low value

Consider clarifying the placeholder notation.

The .{id} notation could be more explicit that it's a placeholder. For an AI agent consuming this skill, consider using .${id} or adding a concrete example like "For a persona with id: blog-writer, the dotfile would be .blog-writer.agentignore."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@personas/skills/relayfile-mount.md` around lines 32 - 33, The placeholder
notation `.{id}.agentignore` and `.{id}.agentreadonly` is ambiguous; update
these entries to use a clearer placeholder like `.${id}.agentignore` and
`.${id}.agentreadonly` or add a concrete example line (e.g., for `id:
blog-writer` show `.blog-writer.agentignore`) so readers and agents understand
that `{id}` is substituted with the persona id.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@personas/skills/relayfile-mount.md`:
- Around line 32-33: The placeholder notation `.{id}.agentignore` and
`.{id}.agentreadonly` is ambiguous; update these entries to use a clearer
placeholder like `.${id}.agentignore` and `.${id}.agentreadonly` or add a
concrete example line (e.g., for `id: blog-writer` show
`.blog-writer.agentignore`) so readers and agents understand that `{id}` is
substituted with the persona id.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 51803e8c-d30a-4235-a2b0-74028ad47bff

📥 Commits

Reviewing files that changed from the base of the PR and between dc4ec59 and bfe36f5.

⛔ Files ignored due to path filters (1)
  • packages/workload-router/src/generated/personas.ts is excluded by !**/generated/**
📒 Files selected for processing (4)
  • personas/persona-maker.json
  • personas/skills/persona-mcp-servers.md
  • personas/skills/persona-sidecars.md
  • personas/skills/relayfile-mount.md
✅ Files skipped from review due to trivial changes (2)
  • personas/skills/persona-sidecars.md
  • personas/skills/persona-mcp-servers.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • personas/persona-maker.json

The previous extraction-into-local-skills approach was broken in the
field. Reported live: persona-maker spawned from a non-workforce cwd
(e.g. ../relay) only loaded `find-skills` — the three local skills
`relayfile-mount`, `persona-mcp-servers`, `persona-sidecars` were
missing from opencode's Skills picker.
Two layered bugs:
1. The agentworkforce binary on PATH is the published 3.0.3 from npm.
Its baked-in catalog has the old persona-maker (only find-skills).
New skills aren't visible until a release lands.
2. Even with the local CLI build, local skill sources resolve relative
paths against process.cwd() at install time. When invoked from
`/tmp/` or any non-workforce repo, `cp personas/skills/<x>.md ...`
fails because the .md files only exist in the workforce source repo.
Three of four skill installs fail with exit code 1.
The proactive-agents pattern (local/<name> source paths) works there
because both the persona AND its skill .md files are co-located in
the same user-repo. Persona-maker is a BUILT-IN shipped via npm —
that pattern doesn't carry across.
Fix: use the agentsMd path-form sidecar. The catalog generator at
`packages/workload-router/scripts/generate-personas.mjs` already
inlines sidecar .md content into agentsMdContent at build time, so
the published package ships a single bundled spec. The .md file is a
real markdown file the author can edit ergonomically; the user sees
the full content in AGENTS.md at session start with no runtime
filesystem lookups required.
Changes:
- New: personas/persona-maker.md — full operating spec including the
Relayfile mount, MCP servers, and Persona sidecar sections that were
previously split into local skill files. Same content the generator
would have inlined; consolidated into one file because cross-cwd
resolution made splitting unworkable.
- personas/persona-maker.json: replace agentsMdContent (inline) with
agentsMd (./persona-maker.md). Drop the three local/ skill entries
from skills[]; only skill.sh/find-skills remains.
- Delete personas/skills/* — content lives in persona-maker.md now.
- Regenerated packages/workload-router/src/generated/personas.ts;
agentsMdContent now 25,371 chars with all three sections inlined.
Verified: dry-run green from /tmp (non-workforce cwd) — the
cross-repo case that previously produced 3 of 4 failed installs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgantkhaliqgant changed the title feat(persona-maker): mount/MCP/sidecar guidance as local skillsfeat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecarMay 13, 2026
Ricky Schema Cascadeand others added 4 commits May 13, 2026 14:04
…m.dev
Previous iterations tried inlining everything in agentsMdContent and then
extracting to local skill .md files referenced via repo-relative paths.
The local-path approach broke cross-repo invocation because local skill
sources resolve against process.cwd() at install time, not the workforce
package install root. Confirmed live: persona-maker spawned from
/Users/khaliqgant/Projects/AgentWorkforce/relay only saw skill.sh/find-skills
in the opencode picker.
Fix: publish the three skills as prpm packages so they're installable from
any cwd via npx -y prpm install <ref>.
Package layout (personas/skills/):
- prpm.json — multi-package manifest following the
@prpm/prpm-json-best-practices-skill structure: top-level metadata
(name, version, author, license, repository, organization), plus a
packages[] with three skill entries (format: generic, subtype: skill).
- LICENSE — MIT, picked up automatically by prpm publish for all packages.
- README.md — discovery / install docs.
- persona-relayfile-mount/SKILL.md — mount field deep dive: allow-list
idiom, !web vs !web/ walker gotcha, readonlyPatterns scope, agentName
overlay, .git sandbox.
- persona-mcp-servers/SKILL.md — mcpServers spec variants, $VAR
substitution, claude/codex/opencode harness matrix, permissions.allow
pairing.
- persona-sidecars/SKILL.md — claudeMd (path) vs claudeMdContent (inline)
distinction; the silent footgun the dry-run does NOT catch.
persona-maker.json:
- skills[] now declares the three @agent-workforce/persona-* refs
alongside skill.sh/find-skills. They install via prpm at session start
and appear in the opencode Skills picker.
- agentsMd: ./persona-maker.md — slim sidecar restored, with the three
embedded sections replaced by pointers to the published skills.
Anti-goals updated to reference the new skill IDs.
Regenerated packages/workload-router/src/generated/personas.ts.
`prpm publish --dry-run` from personas/skills/: ✓ all 3 packages ready
to publish under @agent-workforce/ scope (khaliqgant ✓ as org member).
Publish runs separately (user-driven, not automated in this commit).
After publish lands on prpm.dev, `agentworkforce agent persona-maker
--dry-run` will install all four skills cleanly. Until then the dry-run
exercising the three new skills will fail at the prpm registry lookup
step — expected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…works
Published 1.0.0 with format: generic. Install via `npx -y prpm install
@agent-workforce/persona-relayfile-mount --as opencode` (the command
persona-kit emits for opencode-harness personas) errors with:
Failed to parse generic format: Unsupported source format for
conversion: generic
prpm has format converters keyed off the source format. `generic` has
no converter to `opencode` / `codex` / etc., so install fails the
moment the workforce CLI tries to materialize the skill.
Bump to 1.0.1 with format: claude. SKILL.md with YAML frontmatter is
canonically claude-flavored, and prpm knows how to convert claude →
opencode (verified by installing @agent-relay/choosing-swarm-patterns
with --as opencode: ✓ Converted from claude to opencode).
Dry-run validates clean for all three packages at 1.0.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…eneric
Verified after publish: `prpm show @agent-workforce/persona-relayfile-mount`
returns "Type: generic skill" at version 1.0.1, and `prpm install --as
opencode` still errors "Failed to parse generic format". Either the
publish of 1.0.1 happened before the format-change commit landed in the
working tree, or prpm caches format metadata at first publish — either
way, the remote tarball is still generic.
Bump to 1.0.2 with format: claude. Dry-run confirms:
Package: @agent-workforce/persona-relayfile-mount@1.0.2
Format: claude | Subtype: skill
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The prpm registry route now updates mutable manifest fields on republish
(format, subtype, description, tags, etc.), so the three skills finally
landed as format: claude. Verified end-to-end:
- `prpm show @agent-workforce/persona-relayfile-mount` reports Type:
claude skill at v1.0.3 (previously locked at generic from 1.0.0).
- `agentworkforce agent persona-maker --dry-run` from /tmp:
✓ dry-run ok: 4 skill(s) installed cleanly. All three new skills now
convert claude → opencode and materialize into .opencode/skills/ at
session start.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
khaliqgant merged commit a338122 into mainMay 13, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the persona-maker-mount-mcp-guidance branch May 13, 2026 12:55
Sign up for freeto 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.

1 participant

@khaliqgant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecar - #108

Merged
khaliqgant merged 8 commits into
mainfrom
persona-maker-mount-mcp-guidance
May 13, 2026
Merged

feat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecar#108
khaliqgant merged 8 commits into
mainfrom
persona-maker-mount-mcp-guidance

Conversation

@khaliqgant

@khaliqgantkhaliqgant commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

The persona-maker built-in was missing teaching content for mount, mcpServers, and the silent-footgun distinction between claudeMd (path) and claudeMdContent (inline). A persona authored against the existing spec hit four real failure modes:

  1. claudeMdContent: \"web-blog-content-writer.claudeMdContent.md\" — filename string written verbatim as CLAUDE.md body (dry-run green, agent boots with no spec).
  2. mount.ignoredPatterns: [\"**\", \"!./web/**\"]** breaks ! re-includes; empty mount.
  3. readonlyPatterns: [\"web/**\"] on the persona's own work directory — writes silently dropped on sync-back.
  4. model: \"claude-sonnet\" — bare alias without version, harness errors at spawn.

Changes

New filepersonas/persona-maker.md — the persona's full operating spec, including dedicated sections for Relayfile mount policy (allow-list idiom, the non-obvious !web vs !web/ walker bug, readonlyPatterns scope rule, per-agent dotfile overlay, .git sandbox behavior), MCP servers (two spec variants, \$VAR secret substitution, claude/codex/opencode support matrix, permissions.allow pairing), and Persona sidecar fields (path-vs-inline distinction with explicit "dry-run does NOT catch this" callout).

persona-maker.json:

  • Replaces inline agentsMdContent with agentsMd: \"./persona-maker.md\" (path form). The catalog generator at packages/workload-router/scripts/generate-personas.mjs inlines the .md content into the published spec at build time, so the package still ships a single bundled JSON.
  • New rules in the body: full model identifiers (claude-sonnet-4-6 not claude-sonnet).
  • Anti-goals extended with the four lessons learned plus the mount allow-list !dir (no slash) rule.

Regeneratedpackages/workload-router/src/generated/personas.ts. agentsMdContent is now 25,371 chars and contains all three sections, ready to ship.

Design history

Earlier iterations tried two paths that don't survive cross-repo invocation:

  • Inlining everything in agentsMdContent (one giant escaped string): worked but unmaintainable.
  • Extracting to three local personas/skills/*.md files referenced via local/<name> source paths (the proactive-agents pattern): worked from inside the workforce repo, failed everywhere else. Local skill sources resolve relative paths against process.cwd() at install time; the .md files don't exist in user repos, so cp fails. Reproduced from /tmp/: ✗ 3 of 4 skill(s) failed.

The proactive-agents pattern works because both the persona AND the skill files are co-located in the user's own repo. Persona-maker is a built-in shipped via npm — same pattern doesn't carry.

The agentsMd sidecar approach gets the maintainability win (editable .md file with proper markdown structure) without the cross-repo failure: the generator already inlines the sidecar at build time and the harness loads AGENTS.md from the session cwd, with no runtime filesystem lookups against unfamiliar directories.

Test plan

  • node -e \"require('./personas/persona-maker.json')\" parses; agentsMd resolved to ./persona-maker.md.
  • Catalog generator inlines: published agentsMdContent now 25,371 chars with ## Relayfile mount policy, ## MCP servers, ## Persona sidecar fields.
  • Dry-run from /tmp/ (non-workforce cwd) — the case that previously failed: ✓ dry-run ok: 1 skill(s) installed cleanly.
  • Companion fix in relayfile for the trailing-slash negation walker bug: fix(local-mount): trailing-slash negations now re-include allow-listed directories relayfile#145.

To test locally after merge

The published agentworkforce@3.0.3 on PATH won't pick this up until the next release. To test now:

```bash
cd ~/Projects/AgentWorkforce/workforce
git pull
corepack pnpm install
corepack pnpm --filter @agentworkforce/workload-router --filter @agentworkforce/cli build

From any directory:

node ~/Projects/AgentWorkforce/workforce/packages/cli/dist/cli.js agent persona-maker
```

🤖 Generated with Claude Code

persona-maker.json's AGENTS.md sidecar only listed `mount` and
`mcpServers` as optional fields without explaining when to use them,
the shape, or how harness selection is constrained by MCP support.
Authored personas needing filesystem sandboxing or MCP wiring were a
coin-flip on getting these blocks right.
- Add a `mount` section covering ignoredPatterns/readonlyPatterns
semantics, the `.{persona.id}.agentignore` overlay behavior keyed off
`agentName: persona.id`, the gitignore-negation idiom for allow-lists,
the file-scope-vs-tool-scope split from `permissions`, and the
auto-`.git` sandbox behavior.
- Add an `mcpServers` section with the two spec variants (http/sse vs
stdio), an example of each, `$VAR` substitution policy, and the
claude / codex / opencode support matrix so harness selection is
informed when MCP is required.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR externalizes the persona authoring specification from an inline agentsMdContent field in personas/persona-maker.json into a dedicated personas/persona-maker.md file. The new markdown document provides comprehensive, structured guidance for authoring a Workforce persona, covering required JSON schema, mount policy, MCP servers, sidecar fields, runtime configuration, validation workflow, built-in catalog integration, and explicit anti-goals.

Changes

Persona authoring specification

Layer / File(s)Summary
Persona JSON refactoring and schema foundation
personas/persona-maker.json, personas/persona-maker.md
The JSON file now references ./persona-maker.md instead of embedding agentsMdContent. The new guide introduces required persona JSON shape including id/intent, metadata (tags, description, skills), runtime fields (harness, model, systemPrompt, harnessSettings), and prompt authoring constraints.
Mount policy specification
personas/persona-maker.md, personas/skills/persona-relayfile-mount/SKILL.md
Specifies the mount JSON shape and policy: ignoredPatterns vs readonlyPatterns, per-agent dotfile overlays (.{id}.agentignore/.{id}.agentreadonly), gitignore-style allow-list rules with non-obvious negation requirements, .git sync behavior, and a detailed pre-handoff checklist.
MCP servers specification
personas/persona-maker.md, personas/skills/persona-mcp-servers/SKILL.md
Documents mcpServers configuration including uniform server spec, remote http/sse vs local stdio variants, $VAR/${VAR} secret substitution and unset behavior, harness support matrix, permissions pairing via mcp__* keys, and an MCP authoring checklist.
Sidecar markdown fields specification
personas/persona-maker.md, personas/skills/persona-sidecars/SKILL.md
Defines sidecar fields (claudeMd/agentsMd vs *MdContent), path vs inline semantics and the silent-failure footgun when *MdContent is used incorrectly, *MdMode options (overwrite/extend), and a sidecar authoring checklist.
Runtime, validation, and authoring workflow
personas/persona-maker.md
Lays out runtime defaults for harness, model, reasoning, and timeoutSeconds, describes skill discovery/curation and required agentworkforce agent <id> --dry-run validation checks, details persona prompt authoring steps and built-in catalog integration, lists anti-goals, and specifies the handoff contract.
Skills package manifest, README & LICENSE
personas/skills/prpm.json, personas/skills/README.md, personas/skills/LICENSE
Adds agentworkforce-persona-authoring-skills manifest registering three skills and includes README and MIT license for the skills package.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested reviewers

  • willwashburn

Poem

🐰 The spec hops free from JSON's nest,

A markdown tome emerges dressed,
Mounts and MCPs set in lines,
Sidecars, checklists, clear design,
Persona makers, now you're blessed.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title accurately summarizes the main change: adding guidance documentation for mount/MCP/sidecar features via a persona-maker.md sidecar file referenced in agentsMd.
Description check✅ PassedThe description clearly relates to the changeset, explaining the four failure modes being fixed, the new teaching content added, design decisions, and test plans.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch persona-maker-mount-mcp-guidance

Comment @coderabbitai help to get the list of available commands and usage tips.

@devin-ai-integrationdevin-ai-integrationBot 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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

…ills
The mount and MCP additions from the previous commit made agentsMdContent
even longer. Extract them — plus the silent-footgun guidance about
claudeMdContent vs claudeMd — into three local skill .md files matching
the proactive-agents skill-loading pattern. The skills install into the
session via the local source-kind, so the persona reads them as standalone
SKILL.md files in its working dir instead of carrying everything inline.
Skills:
- personas/skills/relayfile-mount.md — mount field deep dive: allow-list
idiom (/* not **, paired !dir/ + !dir/**), readonlyPatterns scope rule
(never the work dir), agentName overlay, .git sandbox behavior.
- personas/skills/persona-mcp-servers.md — mcpServers two variants
(http/sse vs stdio), $VAR substitution, claude/codex/opencode support
matrix, permissions.allow pairing.
- personas/skills/persona-sidecars.md — claudeMd (path) vs claudeMdContent
(inline) distinction; calls out that the dry-run does NOT catch a path
string mistakenly stored in *MdContent.
persona-maker.json:
- skills[] now declares the three local skills alongside skill.sh/find-skills.
- agentsMdContent trimmed: the long mount/MCP/sidecar paragraphs are
replaced with one-line skill pointers. Net length: 15985 → 15318 chars.
- Anti-goals extended with the four lessons from a recent broken persona:
filename string in *MdContent; ** as broad mount exclude; readonly on
work dir; opencode + mcpServers; bare model alias without version.
- Added 'full model identifiers' rule (claude-sonnet-4-6, not claude-sonnet).
Regenerated packages/workload-router/src/generated/personas.ts to pick up
the new skills.
Dry-run: ✓ 4 skill(s) installed cleanly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgantkhaliqgant changed the title docs(persona-maker): teach mount policy and mcpServers shapefeat(persona-maker): mount/MCP/sidecar guidance as local skillsMay 13, 2026
The "obvious" gitignore allow-list `["/*", "!web/", "!web/**"]` silently
produces an empty mount. Reproduced against relayfile's createMount:
mount root contained only CLAUDE.md, _MOUNT_README.md, and .relayfile-local-mount
— no web/.
Root cause in relayfile-local-mount/src/mount.ts isPathMatched():
return matcher.ignores(relPath) || (isDirectory && matcher.ignores(`${relPath}/`));
The OR short-circuits. For a directory `web`:
- matcher.ignores('web') → true (`/*` matches the bare name)
- matcher.ignores('web/') → false (`!web/` negates the trailing-slash form)
but this branch is never reached.
So `!web/` (slash) only counters the trailing-slash form, leaving the
bare-name check unopposed. The walker treats `web` as ignored and skips
recursion. Verified by harness:
/* + !web/ + !web/** → web (dir) reported as ignored: true (broken)
/* + !web + !web/** → web (dir) reported as ignored: false (correct)
Confirmed end-to-end against a real createMount: with `!web` the mount
root contains web/content/post.md as expected.
Updates:
- relayfile-mount.md skill: add a fourth rule explicitly calling out the
`!dir` vs `!dir/` distinction with the walker's short-circuit as the
reason, plus a "wrong / right" side-by-side. Update the checklist line.
- persona-maker.json anti-goal: replace `!dir/` reference with `!dir`
plus the reason.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitaicoderabbitaiBot 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.

🧹 Nitpick comments (1)
personas/skills/relayfile-mount.md (1)

32-33: 💤 Low value

Consider clarifying the placeholder notation.

The .{id} notation could be more explicit that it's a placeholder. For an AI agent consuming this skill, consider using .${id} or adding a concrete example like "For a persona with id: blog-writer, the dotfile would be .blog-writer.agentignore."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@personas/skills/relayfile-mount.md` around lines 32 - 33, The placeholder
notation `.{id}.agentignore` and `.{id}.agentreadonly` is ambiguous; update
these entries to use a clearer placeholder like `.${id}.agentignore` and
`.${id}.agentreadonly` or add a concrete example line (e.g., for `id:
blog-writer` show `.blog-writer.agentignore`) so readers and agents understand
that `{id}` is substituted with the persona id.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@personas/skills/relayfile-mount.md`:
- Around line 32-33: The placeholder notation `.{id}.agentignore` and
`.{id}.agentreadonly` is ambiguous; update these entries to use a clearer
placeholder like `.${id}.agentignore` and `.${id}.agentreadonly` or add a
concrete example line (e.g., for `id: blog-writer` show
`.blog-writer.agentignore`) so readers and agents understand that `{id}` is
substituted with the persona id.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 51803e8c-d30a-4235-a2b0-74028ad47bff

📥 Commits

Reviewing files that changed from the base of the PR and between dc4ec59 and bfe36f5.

⛔ Files ignored due to path filters (1)
  • packages/workload-router/src/generated/personas.ts is excluded by !**/generated/**
📒 Files selected for processing (4)
  • personas/persona-maker.json
  • personas/skills/persona-mcp-servers.md
  • personas/skills/persona-sidecars.md
  • personas/skills/relayfile-mount.md
✅ Files skipped from review due to trivial changes (2)
  • personas/skills/persona-sidecars.md
  • personas/skills/persona-mcp-servers.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • personas/persona-maker.json

The previous extraction-into-local-skills approach was broken in the
field. Reported live: persona-maker spawned from a non-workforce cwd
(e.g. ../relay) only loaded `find-skills` — the three local skills
`relayfile-mount`, `persona-mcp-servers`, `persona-sidecars` were
missing from opencode's Skills picker.
Two layered bugs:
1. The agentworkforce binary on PATH is the published 3.0.3 from npm.
Its baked-in catalog has the old persona-maker (only find-skills).
New skills aren't visible until a release lands.
2. Even with the local CLI build, local skill sources resolve relative
paths against process.cwd() at install time. When invoked from
`/tmp/` or any non-workforce repo, `cp personas/skills/<x>.md ...`
fails because the .md files only exist in the workforce source repo.
Three of four skill installs fail with exit code 1.
The proactive-agents pattern (local/<name> source paths) works there
because both the persona AND its skill .md files are co-located in
the same user-repo. Persona-maker is a BUILT-IN shipped via npm —
that pattern doesn't carry across.
Fix: use the agentsMd path-form sidecar. The catalog generator at
`packages/workload-router/scripts/generate-personas.mjs` already
inlines sidecar .md content into agentsMdContent at build time, so
the published package ships a single bundled spec. The .md file is a
real markdown file the author can edit ergonomically; the user sees
the full content in AGENTS.md at session start with no runtime
filesystem lookups required.
Changes:
- New: personas/persona-maker.md — full operating spec including the
Relayfile mount, MCP servers, and Persona sidecar sections that were
previously split into local skill files. Same content the generator
would have inlined; consolidated into one file because cross-cwd
resolution made splitting unworkable.
- personas/persona-maker.json: replace agentsMdContent (inline) with
agentsMd (./persona-maker.md). Drop the three local/ skill entries
from skills[]; only skill.sh/find-skills remains.
- Delete personas/skills/* — content lives in persona-maker.md now.
- Regenerated packages/workload-router/src/generated/personas.ts;
agentsMdContent now 25,371 chars with all three sections inlined.
Verified: dry-run green from /tmp (non-workforce cwd) — the
cross-repo case that previously produced 3 of 4 failed installs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgantkhaliqgant changed the title feat(persona-maker): mount/MCP/sidecar guidance as local skillsfeat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecarMay 13, 2026
Ricky Schema Cascadeand others added 4 commits May 13, 2026 14:04
…m.dev
Previous iterations tried inlining everything in agentsMdContent and then
extracting to local skill .md files referenced via repo-relative paths.
The local-path approach broke cross-repo invocation because local skill
sources resolve against process.cwd() at install time, not the workforce
package install root. Confirmed live: persona-maker spawned from
/Users/khaliqgant/Projects/AgentWorkforce/relay only saw skill.sh/find-skills
in the opencode picker.
Fix: publish the three skills as prpm packages so they're installable from
any cwd via npx -y prpm install <ref>.
Package layout (personas/skills/):
- prpm.json — multi-package manifest following the
@prpm/prpm-json-best-practices-skill structure: top-level metadata
(name, version, author, license, repository, organization), plus a
packages[] with three skill entries (format: generic, subtype: skill).
- LICENSE — MIT, picked up automatically by prpm publish for all packages.
- README.md — discovery / install docs.
- persona-relayfile-mount/SKILL.md — mount field deep dive: allow-list
idiom, !web vs !web/ walker gotcha, readonlyPatterns scope, agentName
overlay, .git sandbox.
- persona-mcp-servers/SKILL.md — mcpServers spec variants, $VAR
substitution, claude/codex/opencode harness matrix, permissions.allow
pairing.
- persona-sidecars/SKILL.md — claudeMd (path) vs claudeMdContent (inline)
distinction; the silent footgun the dry-run does NOT catch.
persona-maker.json:
- skills[] now declares the three @agent-workforce/persona-* refs
alongside skill.sh/find-skills. They install via prpm at session start
and appear in the opencode Skills picker.
- agentsMd: ./persona-maker.md — slim sidecar restored, with the three
embedded sections replaced by pointers to the published skills.
Anti-goals updated to reference the new skill IDs.
Regenerated packages/workload-router/src/generated/personas.ts.
`prpm publish --dry-run` from personas/skills/: ✓ all 3 packages ready
to publish under @agent-workforce/ scope (khaliqgant ✓ as org member).
Publish runs separately (user-driven, not automated in this commit).
After publish lands on prpm.dev, `agentworkforce agent persona-maker
--dry-run` will install all four skills cleanly. Until then the dry-run
exercising the three new skills will fail at the prpm registry lookup
step — expected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…works
Published 1.0.0 with format: generic. Install via `npx -y prpm install
@agent-workforce/persona-relayfile-mount --as opencode` (the command
persona-kit emits for opencode-harness personas) errors with:
Failed to parse generic format: Unsupported source format for
conversion: generic
prpm has format converters keyed off the source format. `generic` has
no converter to `opencode` / `codex` / etc., so install fails the
moment the workforce CLI tries to materialize the skill.
Bump to 1.0.1 with format: claude. SKILL.md with YAML frontmatter is
canonically claude-flavored, and prpm knows how to convert claude →
opencode (verified by installing @agent-relay/choosing-swarm-patterns
with --as opencode: ✓ Converted from claude to opencode).
Dry-run validates clean for all three packages at 1.0.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…eneric
Verified after publish: `prpm show @agent-workforce/persona-relayfile-mount`
returns "Type: generic skill" at version 1.0.1, and `prpm install --as
opencode` still errors "Failed to parse generic format". Either the
publish of 1.0.1 happened before the format-change commit landed in the
working tree, or prpm caches format metadata at first publish — either
way, the remote tarball is still generic.
Bump to 1.0.2 with format: claude. Dry-run confirms:
Package: @agent-workforce/persona-relayfile-mount@1.0.2
Format: claude | Subtype: skill
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The prpm registry route now updates mutable manifest fields on republish
(format, subtype, description, tags, etc.), so the three skills finally
landed as format: claude. Verified end-to-end:
- `prpm show @agent-workforce/persona-relayfile-mount` reports Type:
claude skill at v1.0.3 (previously locked at generic from 1.0.0).
- `agentworkforce agent persona-maker --dry-run` from /tmp:
✓ dry-run ok: 4 skill(s) installed cleanly. All three new skills now
convert claude → opencode and materialize into .opencode/skills/ at
session start.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
khaliqgant merged commit a338122 into mainMay 13, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the persona-maker-mount-mcp-guidance branch May 13, 2026 12:55
Sign up for freeto 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.

1 participant

@khaliqgant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecar - #108

Merged
khaliqgant merged 8 commits into
mainfrom
persona-maker-mount-mcp-guidance
May 13, 2026
Merged

feat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecar#108
khaliqgant merged 8 commits into
mainfrom
persona-maker-mount-mcp-guidance

Conversation

@khaliqgant

@khaliqgantkhaliqgant commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

The persona-maker built-in was missing teaching content for mount, mcpServers, and the silent-footgun distinction between claudeMd (path) and claudeMdContent (inline). A persona authored against the existing spec hit four real failure modes:

  1. claudeMdContent: \"web-blog-content-writer.claudeMdContent.md\" — filename string written verbatim as CLAUDE.md body (dry-run green, agent boots with no spec).
  2. mount.ignoredPatterns: [\"**\", \"!./web/**\"]** breaks ! re-includes; empty mount.
  3. readonlyPatterns: [\"web/**\"] on the persona's own work directory — writes silently dropped on sync-back.
  4. model: \"claude-sonnet\" — bare alias without version, harness errors at spawn.

Changes

New filepersonas/persona-maker.md — the persona's full operating spec, including dedicated sections for Relayfile mount policy (allow-list idiom, the non-obvious !web vs !web/ walker bug, readonlyPatterns scope rule, per-agent dotfile overlay, .git sandbox behavior), MCP servers (two spec variants, \$VAR secret substitution, claude/codex/opencode support matrix, permissions.allow pairing), and Persona sidecar fields (path-vs-inline distinction with explicit "dry-run does NOT catch this" callout).

persona-maker.json:

  • Replaces inline agentsMdContent with agentsMd: \"./persona-maker.md\" (path form). The catalog generator at packages/workload-router/scripts/generate-personas.mjs inlines the .md content into the published spec at build time, so the package still ships a single bundled JSON.
  • New rules in the body: full model identifiers (claude-sonnet-4-6 not claude-sonnet).
  • Anti-goals extended with the four lessons learned plus the mount allow-list !dir (no slash) rule.

Regeneratedpackages/workload-router/src/generated/personas.ts. agentsMdContent is now 25,371 chars and contains all three sections, ready to ship.

Design history

Earlier iterations tried two paths that don't survive cross-repo invocation:

  • Inlining everything in agentsMdContent (one giant escaped string): worked but unmaintainable.
  • Extracting to three local personas/skills/*.md files referenced via local/<name> source paths (the proactive-agents pattern): worked from inside the workforce repo, failed everywhere else. Local skill sources resolve relative paths against process.cwd() at install time; the .md files don't exist in user repos, so cp fails. Reproduced from /tmp/: ✗ 3 of 4 skill(s) failed.

The proactive-agents pattern works because both the persona AND the skill files are co-located in the user's own repo. Persona-maker is a built-in shipped via npm — same pattern doesn't carry.

The agentsMd sidecar approach gets the maintainability win (editable .md file with proper markdown structure) without the cross-repo failure: the generator already inlines the sidecar at build time and the harness loads AGENTS.md from the session cwd, with no runtime filesystem lookups against unfamiliar directories.

Test plan

  • node -e \"require('./personas/persona-maker.json')\" parses; agentsMd resolved to ./persona-maker.md.
  • Catalog generator inlines: published agentsMdContent now 25,371 chars with ## Relayfile mount policy, ## MCP servers, ## Persona sidecar fields.
  • Dry-run from /tmp/ (non-workforce cwd) — the case that previously failed: ✓ dry-run ok: 1 skill(s) installed cleanly.
  • Companion fix in relayfile for the trailing-slash negation walker bug: fix(local-mount): trailing-slash negations now re-include allow-listed directories relayfile#145.

To test locally after merge

The published agentworkforce@3.0.3 on PATH won't pick this up until the next release. To test now:

```bash
cd ~/Projects/AgentWorkforce/workforce
git pull
corepack pnpm install
corepack pnpm --filter @agentworkforce/workload-router --filter @agentworkforce/cli build

From any directory:

node ~/Projects/AgentWorkforce/workforce/packages/cli/dist/cli.js agent persona-maker
```

🤖 Generated with Claude Code

persona-maker.json's AGENTS.md sidecar only listed `mount` and
`mcpServers` as optional fields without explaining when to use them,
the shape, or how harness selection is constrained by MCP support.
Authored personas needing filesystem sandboxing or MCP wiring were a
coin-flip on getting these blocks right.
- Add a `mount` section covering ignoredPatterns/readonlyPatterns
semantics, the `.{persona.id}.agentignore` overlay behavior keyed off
`agentName: persona.id`, the gitignore-negation idiom for allow-lists,
the file-scope-vs-tool-scope split from `permissions`, and the
auto-`.git` sandbox behavior.
- Add an `mcpServers` section with the two spec variants (http/sse vs
stdio), an example of each, `$VAR` substitution policy, and the
claude / codex / opencode support matrix so harness selection is
informed when MCP is required.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR externalizes the persona authoring specification from an inline agentsMdContent field in personas/persona-maker.json into a dedicated personas/persona-maker.md file. The new markdown document provides comprehensive, structured guidance for authoring a Workforce persona, covering required JSON schema, mount policy, MCP servers, sidecar fields, runtime configuration, validation workflow, built-in catalog integration, and explicit anti-goals.

Changes

Persona authoring specification

Layer / File(s)Summary
Persona JSON refactoring and schema foundation
personas/persona-maker.json, personas/persona-maker.md
The JSON file now references ./persona-maker.md instead of embedding agentsMdContent. The new guide introduces required persona JSON shape including id/intent, metadata (tags, description, skills), runtime fields (harness, model, systemPrompt, harnessSettings), and prompt authoring constraints.
Mount policy specification
personas/persona-maker.md, personas/skills/persona-relayfile-mount/SKILL.md
Specifies the mount JSON shape and policy: ignoredPatterns vs readonlyPatterns, per-agent dotfile overlays (.{id}.agentignore/.{id}.agentreadonly), gitignore-style allow-list rules with non-obvious negation requirements, .git sync behavior, and a detailed pre-handoff checklist.
MCP servers specification
personas/persona-maker.md, personas/skills/persona-mcp-servers/SKILL.md
Documents mcpServers configuration including uniform server spec, remote http/sse vs local stdio variants, $VAR/${VAR} secret substitution and unset behavior, harness support matrix, permissions pairing via mcp__* keys, and an MCP authoring checklist.
Sidecar markdown fields specification
personas/persona-maker.md, personas/skills/persona-sidecars/SKILL.md
Defines sidecar fields (claudeMd/agentsMd vs *MdContent), path vs inline semantics and the silent-failure footgun when *MdContent is used incorrectly, *MdMode options (overwrite/extend), and a sidecar authoring checklist.
Runtime, validation, and authoring workflow
personas/persona-maker.md
Lays out runtime defaults for harness, model, reasoning, and timeoutSeconds, describes skill discovery/curation and required agentworkforce agent <id> --dry-run validation checks, details persona prompt authoring steps and built-in catalog integration, lists anti-goals, and specifies the handoff contract.
Skills package manifest, README & LICENSE
personas/skills/prpm.json, personas/skills/README.md, personas/skills/LICENSE
Adds agentworkforce-persona-authoring-skills manifest registering three skills and includes README and MIT license for the skills package.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested reviewers

  • willwashburn

Poem

🐰 The spec hops free from JSON's nest,

A markdown tome emerges dressed,
Mounts and MCPs set in lines,
Sidecars, checklists, clear design,
Persona makers, now you're blessed.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title accurately summarizes the main change: adding guidance documentation for mount/MCP/sidecar features via a persona-maker.md sidecar file referenced in agentsMd.
Description check✅ PassedThe description clearly relates to the changeset, explaining the four failure modes being fixed, the new teaching content added, design decisions, and test plans.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch persona-maker-mount-mcp-guidance

Comment @coderabbitai help to get the list of available commands and usage tips.

@devin-ai-integrationdevin-ai-integrationBot 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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

…ills
The mount and MCP additions from the previous commit made agentsMdContent
even longer. Extract them — plus the silent-footgun guidance about
claudeMdContent vs claudeMd — into three local skill .md files matching
the proactive-agents skill-loading pattern. The skills install into the
session via the local source-kind, so the persona reads them as standalone
SKILL.md files in its working dir instead of carrying everything inline.
Skills:
- personas/skills/relayfile-mount.md — mount field deep dive: allow-list
idiom (/* not **, paired !dir/ + !dir/**), readonlyPatterns scope rule
(never the work dir), agentName overlay, .git sandbox behavior.
- personas/skills/persona-mcp-servers.md — mcpServers two variants
(http/sse vs stdio), $VAR substitution, claude/codex/opencode support
matrix, permissions.allow pairing.
- personas/skills/persona-sidecars.md — claudeMd (path) vs claudeMdContent
(inline) distinction; calls out that the dry-run does NOT catch a path
string mistakenly stored in *MdContent.
persona-maker.json:
- skills[] now declares the three local skills alongside skill.sh/find-skills.
- agentsMdContent trimmed: the long mount/MCP/sidecar paragraphs are
replaced with one-line skill pointers. Net length: 15985 → 15318 chars.
- Anti-goals extended with the four lessons from a recent broken persona:
filename string in *MdContent; ** as broad mount exclude; readonly on
work dir; opencode + mcpServers; bare model alias without version.
- Added 'full model identifiers' rule (claude-sonnet-4-6, not claude-sonnet).
Regenerated packages/workload-router/src/generated/personas.ts to pick up
the new skills.
Dry-run: ✓ 4 skill(s) installed cleanly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgantkhaliqgant changed the title docs(persona-maker): teach mount policy and mcpServers shapefeat(persona-maker): mount/MCP/sidecar guidance as local skillsMay 13, 2026
The "obvious" gitignore allow-list `["/*", "!web/", "!web/**"]` silently
produces an empty mount. Reproduced against relayfile's createMount:
mount root contained only CLAUDE.md, _MOUNT_README.md, and .relayfile-local-mount
— no web/.
Root cause in relayfile-local-mount/src/mount.ts isPathMatched():
return matcher.ignores(relPath) || (isDirectory && matcher.ignores(`${relPath}/`));
The OR short-circuits. For a directory `web`:
- matcher.ignores('web') → true (`/*` matches the bare name)
- matcher.ignores('web/') → false (`!web/` negates the trailing-slash form)
but this branch is never reached.
So `!web/` (slash) only counters the trailing-slash form, leaving the
bare-name check unopposed. The walker treats `web` as ignored and skips
recursion. Verified by harness:
/* + !web/ + !web/** → web (dir) reported as ignored: true (broken)
/* + !web + !web/** → web (dir) reported as ignored: false (correct)
Confirmed end-to-end against a real createMount: with `!web` the mount
root contains web/content/post.md as expected.
Updates:
- relayfile-mount.md skill: add a fourth rule explicitly calling out the
`!dir` vs `!dir/` distinction with the walker's short-circuit as the
reason, plus a "wrong / right" side-by-side. Update the checklist line.
- persona-maker.json anti-goal: replace `!dir/` reference with `!dir`
plus the reason.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitaicoderabbitaiBot 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.

🧹 Nitpick comments (1)
personas/skills/relayfile-mount.md (1)

32-33: 💤 Low value

Consider clarifying the placeholder notation.

The .{id} notation could be more explicit that it's a placeholder. For an AI agent consuming this skill, consider using .${id} or adding a concrete example like "For a persona with id: blog-writer, the dotfile would be .blog-writer.agentignore."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@personas/skills/relayfile-mount.md` around lines 32 - 33, The placeholder
notation `.{id}.agentignore` and `.{id}.agentreadonly` is ambiguous; update
these entries to use a clearer placeholder like `.${id}.agentignore` and
`.${id}.agentreadonly` or add a concrete example line (e.g., for `id:
blog-writer` show `.blog-writer.agentignore`) so readers and agents understand
that `{id}` is substituted with the persona id.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@personas/skills/relayfile-mount.md`:
- Around line 32-33: The placeholder notation `.{id}.agentignore` and
`.{id}.agentreadonly` is ambiguous; update these entries to use a clearer
placeholder like `.${id}.agentignore` and `.${id}.agentreadonly` or add a
concrete example line (e.g., for `id: blog-writer` show
`.blog-writer.agentignore`) so readers and agents understand that `{id}` is
substituted with the persona id.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 51803e8c-d30a-4235-a2b0-74028ad47bff

📥 Commits

Reviewing files that changed from the base of the PR and between dc4ec59 and bfe36f5.

⛔ Files ignored due to path filters (1)
  • packages/workload-router/src/generated/personas.ts is excluded by !**/generated/**
📒 Files selected for processing (4)
  • personas/persona-maker.json
  • personas/skills/persona-mcp-servers.md
  • personas/skills/persona-sidecars.md
  • personas/skills/relayfile-mount.md
✅ Files skipped from review due to trivial changes (2)
  • personas/skills/persona-sidecars.md
  • personas/skills/persona-mcp-servers.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • personas/persona-maker.json

The previous extraction-into-local-skills approach was broken in the
field. Reported live: persona-maker spawned from a non-workforce cwd
(e.g. ../relay) only loaded `find-skills` — the three local skills
`relayfile-mount`, `persona-mcp-servers`, `persona-sidecars` were
missing from opencode's Skills picker.
Two layered bugs:
1. The agentworkforce binary on PATH is the published 3.0.3 from npm.
Its baked-in catalog has the old persona-maker (only find-skills).
New skills aren't visible until a release lands.
2. Even with the local CLI build, local skill sources resolve relative
paths against process.cwd() at install time. When invoked from
`/tmp/` or any non-workforce repo, `cp personas/skills/<x>.md ...`
fails because the .md files only exist in the workforce source repo.
Three of four skill installs fail with exit code 1.
The proactive-agents pattern (local/<name> source paths) works there
because both the persona AND its skill .md files are co-located in
the same user-repo. Persona-maker is a BUILT-IN shipped via npm —
that pattern doesn't carry across.
Fix: use the agentsMd path-form sidecar. The catalog generator at
`packages/workload-router/scripts/generate-personas.mjs` already
inlines sidecar .md content into agentsMdContent at build time, so
the published package ships a single bundled spec. The .md file is a
real markdown file the author can edit ergonomically; the user sees
the full content in AGENTS.md at session start with no runtime
filesystem lookups required.
Changes:
- New: personas/persona-maker.md — full operating spec including the
Relayfile mount, MCP servers, and Persona sidecar sections that were
previously split into local skill files. Same content the generator
would have inlined; consolidated into one file because cross-cwd
resolution made splitting unworkable.
- personas/persona-maker.json: replace agentsMdContent (inline) with
agentsMd (./persona-maker.md). Drop the three local/ skill entries
from skills[]; only skill.sh/find-skills remains.
- Delete personas/skills/* — content lives in persona-maker.md now.
- Regenerated packages/workload-router/src/generated/personas.ts;
agentsMdContent now 25,371 chars with all three sections inlined.
Verified: dry-run green from /tmp (non-workforce cwd) — the
cross-repo case that previously produced 3 of 4 failed installs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgantkhaliqgant changed the title feat(persona-maker): mount/MCP/sidecar guidance as local skillsfeat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecarMay 13, 2026
Ricky Schema Cascadeand others added 4 commits May 13, 2026 14:04
…m.dev
Previous iterations tried inlining everything in agentsMdContent and then
extracting to local skill .md files referenced via repo-relative paths.
The local-path approach broke cross-repo invocation because local skill
sources resolve against process.cwd() at install time, not the workforce
package install root. Confirmed live: persona-maker spawned from
/Users/khaliqgant/Projects/AgentWorkforce/relay only saw skill.sh/find-skills
in the opencode picker.
Fix: publish the three skills as prpm packages so they're installable from
any cwd via npx -y prpm install <ref>.
Package layout (personas/skills/):
- prpm.json — multi-package manifest following the
@prpm/prpm-json-best-practices-skill structure: top-level metadata
(name, version, author, license, repository, organization), plus a
packages[] with three skill entries (format: generic, subtype: skill).
- LICENSE — MIT, picked up automatically by prpm publish for all packages.
- README.md — discovery / install docs.
- persona-relayfile-mount/SKILL.md — mount field deep dive: allow-list
idiom, !web vs !web/ walker gotcha, readonlyPatterns scope, agentName
overlay, .git sandbox.
- persona-mcp-servers/SKILL.md — mcpServers spec variants, $VAR
substitution, claude/codex/opencode harness matrix, permissions.allow
pairing.
- persona-sidecars/SKILL.md — claudeMd (path) vs claudeMdContent (inline)
distinction; the silent footgun the dry-run does NOT catch.
persona-maker.json:
- skills[] now declares the three @agent-workforce/persona-* refs
alongside skill.sh/find-skills. They install via prpm at session start
and appear in the opencode Skills picker.
- agentsMd: ./persona-maker.md — slim sidecar restored, with the three
embedded sections replaced by pointers to the published skills.
Anti-goals updated to reference the new skill IDs.
Regenerated packages/workload-router/src/generated/personas.ts.
`prpm publish --dry-run` from personas/skills/: ✓ all 3 packages ready
to publish under @agent-workforce/ scope (khaliqgant ✓ as org member).
Publish runs separately (user-driven, not automated in this commit).
After publish lands on prpm.dev, `agentworkforce agent persona-maker
--dry-run` will install all four skills cleanly. Until then the dry-run
exercising the three new skills will fail at the prpm registry lookup
step — expected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…works
Published 1.0.0 with format: generic. Install via `npx -y prpm install
@agent-workforce/persona-relayfile-mount --as opencode` (the command
persona-kit emits for opencode-harness personas) errors with:
Failed to parse generic format: Unsupported source format for
conversion: generic
prpm has format converters keyed off the source format. `generic` has
no converter to `opencode` / `codex` / etc., so install fails the
moment the workforce CLI tries to materialize the skill.
Bump to 1.0.1 with format: claude. SKILL.md with YAML frontmatter is
canonically claude-flavored, and prpm knows how to convert claude →
opencode (verified by installing @agent-relay/choosing-swarm-patterns
with --as opencode: ✓ Converted from claude to opencode).
Dry-run validates clean for all three packages at 1.0.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…eneric
Verified after publish: `prpm show @agent-workforce/persona-relayfile-mount`
returns "Type: generic skill" at version 1.0.1, and `prpm install --as
opencode` still errors "Failed to parse generic format". Either the
publish of 1.0.1 happened before the format-change commit landed in the
working tree, or prpm caches format metadata at first publish — either
way, the remote tarball is still generic.
Bump to 1.0.2 with format: claude. Dry-run confirms:
Package: @agent-workforce/persona-relayfile-mount@1.0.2
Format: claude | Subtype: skill
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The prpm registry route now updates mutable manifest fields on republish
(format, subtype, description, tags, etc.), so the three skills finally
landed as format: claude. Verified end-to-end:
- `prpm show @agent-workforce/persona-relayfile-mount` reports Type:
claude skill at v1.0.3 (previously locked at generic from 1.0.0).
- `agentworkforce agent persona-maker --dry-run` from /tmp:
✓ dry-run ok: 4 skill(s) installed cleanly. All three new skills now
convert claude → opencode and materialize into .opencode/skills/ at
session start.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
khaliqgant merged commit a338122 into mainMay 13, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the persona-maker-mount-mcp-guidance branch May 13, 2026 12:55
Sign up for freeto 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.

1 participant

@khaliqgant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecar - #108

Merged
khaliqgant merged 8 commits into
mainfrom
persona-maker-mount-mcp-guidance
May 13, 2026
Merged

feat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecar#108
khaliqgant merged 8 commits into
mainfrom
persona-maker-mount-mcp-guidance

Conversation

@khaliqgant

@khaliqgantkhaliqgant commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

The persona-maker built-in was missing teaching content for mount, mcpServers, and the silent-footgun distinction between claudeMd (path) and claudeMdContent (inline). A persona authored against the existing spec hit four real failure modes:

  1. claudeMdContent: \"web-blog-content-writer.claudeMdContent.md\" — filename string written verbatim as CLAUDE.md body (dry-run green, agent boots with no spec).
  2. mount.ignoredPatterns: [\"**\", \"!./web/**\"]** breaks ! re-includes; empty mount.
  3. readonlyPatterns: [\"web/**\"] on the persona's own work directory — writes silently dropped on sync-back.
  4. model: \"claude-sonnet\" — bare alias without version, harness errors at spawn.

Changes

New filepersonas/persona-maker.md — the persona's full operating spec, including dedicated sections for Relayfile mount policy (allow-list idiom, the non-obvious !web vs !web/ walker bug, readonlyPatterns scope rule, per-agent dotfile overlay, .git sandbox behavior), MCP servers (two spec variants, \$VAR secret substitution, claude/codex/opencode support matrix, permissions.allow pairing), and Persona sidecar fields (path-vs-inline distinction with explicit "dry-run does NOT catch this" callout).

persona-maker.json:

  • Replaces inline agentsMdContent with agentsMd: \"./persona-maker.md\" (path form). The catalog generator at packages/workload-router/scripts/generate-personas.mjs inlines the .md content into the published spec at build time, so the package still ships a single bundled JSON.
  • New rules in the body: full model identifiers (claude-sonnet-4-6 not claude-sonnet).
  • Anti-goals extended with the four lessons learned plus the mount allow-list !dir (no slash) rule.

Regeneratedpackages/workload-router/src/generated/personas.ts. agentsMdContent is now 25,371 chars and contains all three sections, ready to ship.

Design history

Earlier iterations tried two paths that don't survive cross-repo invocation:

  • Inlining everything in agentsMdContent (one giant escaped string): worked but unmaintainable.
  • Extracting to three local personas/skills/*.md files referenced via local/<name> source paths (the proactive-agents pattern): worked from inside the workforce repo, failed everywhere else. Local skill sources resolve relative paths against process.cwd() at install time; the .md files don't exist in user repos, so cp fails. Reproduced from /tmp/: ✗ 3 of 4 skill(s) failed.

The proactive-agents pattern works because both the persona AND the skill files are co-located in the user's own repo. Persona-maker is a built-in shipped via npm — same pattern doesn't carry.

The agentsMd sidecar approach gets the maintainability win (editable .md file with proper markdown structure) without the cross-repo failure: the generator already inlines the sidecar at build time and the harness loads AGENTS.md from the session cwd, with no runtime filesystem lookups against unfamiliar directories.

Test plan

  • node -e \"require('./personas/persona-maker.json')\" parses; agentsMd resolved to ./persona-maker.md.
  • Catalog generator inlines: published agentsMdContent now 25,371 chars with ## Relayfile mount policy, ## MCP servers, ## Persona sidecar fields.
  • Dry-run from /tmp/ (non-workforce cwd) — the case that previously failed: ✓ dry-run ok: 1 skill(s) installed cleanly.
  • Companion fix in relayfile for the trailing-slash negation walker bug: fix(local-mount): trailing-slash negations now re-include allow-listed directories relayfile#145.

To test locally after merge

The published agentworkforce@3.0.3 on PATH won't pick this up until the next release. To test now:

```bash
cd ~/Projects/AgentWorkforce/workforce
git pull
corepack pnpm install
corepack pnpm --filter @agentworkforce/workload-router --filter @agentworkforce/cli build

From any directory:

node ~/Projects/AgentWorkforce/workforce/packages/cli/dist/cli.js agent persona-maker
```

🤖 Generated with Claude Code

persona-maker.json's AGENTS.md sidecar only listed `mount` and
`mcpServers` as optional fields without explaining when to use them,
the shape, or how harness selection is constrained by MCP support.
Authored personas needing filesystem sandboxing or MCP wiring were a
coin-flip on getting these blocks right.
- Add a `mount` section covering ignoredPatterns/readonlyPatterns
semantics, the `.{persona.id}.agentignore` overlay behavior keyed off
`agentName: persona.id`, the gitignore-negation idiom for allow-lists,
the file-scope-vs-tool-scope split from `permissions`, and the
auto-`.git` sandbox behavior.
- Add an `mcpServers` section with the two spec variants (http/sse vs
stdio), an example of each, `$VAR` substitution policy, and the
claude / codex / opencode support matrix so harness selection is
informed when MCP is required.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR externalizes the persona authoring specification from an inline agentsMdContent field in personas/persona-maker.json into a dedicated personas/persona-maker.md file. The new markdown document provides comprehensive, structured guidance for authoring a Workforce persona, covering required JSON schema, mount policy, MCP servers, sidecar fields, runtime configuration, validation workflow, built-in catalog integration, and explicit anti-goals.

Changes

Persona authoring specification

Layer / File(s)Summary
Persona JSON refactoring and schema foundation
personas/persona-maker.json, personas/persona-maker.md
The JSON file now references ./persona-maker.md instead of embedding agentsMdContent. The new guide introduces required persona JSON shape including id/intent, metadata (tags, description, skills), runtime fields (harness, model, systemPrompt, harnessSettings), and prompt authoring constraints.
Mount policy specification
personas/persona-maker.md, personas/skills/persona-relayfile-mount/SKILL.md
Specifies the mount JSON shape and policy: ignoredPatterns vs readonlyPatterns, per-agent dotfile overlays (.{id}.agentignore/.{id}.agentreadonly), gitignore-style allow-list rules with non-obvious negation requirements, .git sync behavior, and a detailed pre-handoff checklist.
MCP servers specification
personas/persona-maker.md, personas/skills/persona-mcp-servers/SKILL.md
Documents mcpServers configuration including uniform server spec, remote http/sse vs local stdio variants, $VAR/${VAR} secret substitution and unset behavior, harness support matrix, permissions pairing via mcp__* keys, and an MCP authoring checklist.
Sidecar markdown fields specification
personas/persona-maker.md, personas/skills/persona-sidecars/SKILL.md
Defines sidecar fields (claudeMd/agentsMd vs *MdContent), path vs inline semantics and the silent-failure footgun when *MdContent is used incorrectly, *MdMode options (overwrite/extend), and a sidecar authoring checklist.
Runtime, validation, and authoring workflow
personas/persona-maker.md
Lays out runtime defaults for harness, model, reasoning, and timeoutSeconds, describes skill discovery/curation and required agentworkforce agent <id> --dry-run validation checks, details persona prompt authoring steps and built-in catalog integration, lists anti-goals, and specifies the handoff contract.
Skills package manifest, README & LICENSE
personas/skills/prpm.json, personas/skills/README.md, personas/skills/LICENSE
Adds agentworkforce-persona-authoring-skills manifest registering three skills and includes README and MIT license for the skills package.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested reviewers

  • willwashburn

Poem

🐰 The spec hops free from JSON's nest,

A markdown tome emerges dressed,
Mounts and MCPs set in lines,
Sidecars, checklists, clear design,
Persona makers, now you're blessed.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title accurately summarizes the main change: adding guidance documentation for mount/MCP/sidecar features via a persona-maker.md sidecar file referenced in agentsMd.
Description check✅ PassedThe description clearly relates to the changeset, explaining the four failure modes being fixed, the new teaching content added, design decisions, and test plans.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch persona-maker-mount-mcp-guidance

Comment @coderabbitai help to get the list of available commands and usage tips.

@devin-ai-integrationdevin-ai-integrationBot 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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

…ills
The mount and MCP additions from the previous commit made agentsMdContent
even longer. Extract them — plus the silent-footgun guidance about
claudeMdContent vs claudeMd — into three local skill .md files matching
the proactive-agents skill-loading pattern. The skills install into the
session via the local source-kind, so the persona reads them as standalone
SKILL.md files in its working dir instead of carrying everything inline.
Skills:
- personas/skills/relayfile-mount.md — mount field deep dive: allow-list
idiom (/* not **, paired !dir/ + !dir/**), readonlyPatterns scope rule
(never the work dir), agentName overlay, .git sandbox behavior.
- personas/skills/persona-mcp-servers.md — mcpServers two variants
(http/sse vs stdio), $VAR substitution, claude/codex/opencode support
matrix, permissions.allow pairing.
- personas/skills/persona-sidecars.md — claudeMd (path) vs claudeMdContent
(inline) distinction; calls out that the dry-run does NOT catch a path
string mistakenly stored in *MdContent.
persona-maker.json:
- skills[] now declares the three local skills alongside skill.sh/find-skills.
- agentsMdContent trimmed: the long mount/MCP/sidecar paragraphs are
replaced with one-line skill pointers. Net length: 15985 → 15318 chars.
- Anti-goals extended with the four lessons from a recent broken persona:
filename string in *MdContent; ** as broad mount exclude; readonly on
work dir; opencode + mcpServers; bare model alias without version.
- Added 'full model identifiers' rule (claude-sonnet-4-6, not claude-sonnet).
Regenerated packages/workload-router/src/generated/personas.ts to pick up
the new skills.
Dry-run: ✓ 4 skill(s) installed cleanly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgantkhaliqgant changed the title docs(persona-maker): teach mount policy and mcpServers shapefeat(persona-maker): mount/MCP/sidecar guidance as local skillsMay 13, 2026
The "obvious" gitignore allow-list `["/*", "!web/", "!web/**"]` silently
produces an empty mount. Reproduced against relayfile's createMount:
mount root contained only CLAUDE.md, _MOUNT_README.md, and .relayfile-local-mount
— no web/.
Root cause in relayfile-local-mount/src/mount.ts isPathMatched():
return matcher.ignores(relPath) || (isDirectory && matcher.ignores(`${relPath}/`));
The OR short-circuits. For a directory `web`:
- matcher.ignores('web') → true (`/*` matches the bare name)
- matcher.ignores('web/') → false (`!web/` negates the trailing-slash form)
but this branch is never reached.
So `!web/` (slash) only counters the trailing-slash form, leaving the
bare-name check unopposed. The walker treats `web` as ignored and skips
recursion. Verified by harness:
/* + !web/ + !web/** → web (dir) reported as ignored: true (broken)
/* + !web + !web/** → web (dir) reported as ignored: false (correct)
Confirmed end-to-end against a real createMount: with `!web` the mount
root contains web/content/post.md as expected.
Updates:
- relayfile-mount.md skill: add a fourth rule explicitly calling out the
`!dir` vs `!dir/` distinction with the walker's short-circuit as the
reason, plus a "wrong / right" side-by-side. Update the checklist line.
- persona-maker.json anti-goal: replace `!dir/` reference with `!dir`
plus the reason.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitaicoderabbitaiBot 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.

🧹 Nitpick comments (1)
personas/skills/relayfile-mount.md (1)

32-33: 💤 Low value

Consider clarifying the placeholder notation.

The .{id} notation could be more explicit that it's a placeholder. For an AI agent consuming this skill, consider using .${id} or adding a concrete example like "For a persona with id: blog-writer, the dotfile would be .blog-writer.agentignore."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@personas/skills/relayfile-mount.md` around lines 32 - 33, The placeholder
notation `.{id}.agentignore` and `.{id}.agentreadonly` is ambiguous; update
these entries to use a clearer placeholder like `.${id}.agentignore` and
`.${id}.agentreadonly` or add a concrete example line (e.g., for `id:
blog-writer` show `.blog-writer.agentignore`) so readers and agents understand
that `{id}` is substituted with the persona id.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@personas/skills/relayfile-mount.md`:
- Around line 32-33: The placeholder notation `.{id}.agentignore` and
`.{id}.agentreadonly` is ambiguous; update these entries to use a clearer
placeholder like `.${id}.agentignore` and `.${id}.agentreadonly` or add a
concrete example line (e.g., for `id: blog-writer` show
`.blog-writer.agentignore`) so readers and agents understand that `{id}` is
substituted with the persona id.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 51803e8c-d30a-4235-a2b0-74028ad47bff

📥 Commits

Reviewing files that changed from the base of the PR and between dc4ec59 and bfe36f5.

⛔ Files ignored due to path filters (1)
  • packages/workload-router/src/generated/personas.ts is excluded by !**/generated/**
📒 Files selected for processing (4)
  • personas/persona-maker.json
  • personas/skills/persona-mcp-servers.md
  • personas/skills/persona-sidecars.md
  • personas/skills/relayfile-mount.md
✅ Files skipped from review due to trivial changes (2)
  • personas/skills/persona-sidecars.md
  • personas/skills/persona-mcp-servers.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • personas/persona-maker.json

The previous extraction-into-local-skills approach was broken in the
field. Reported live: persona-maker spawned from a non-workforce cwd
(e.g. ../relay) only loaded `find-skills` — the three local skills
`relayfile-mount`, `persona-mcp-servers`, `persona-sidecars` were
missing from opencode's Skills picker.
Two layered bugs:
1. The agentworkforce binary on PATH is the published 3.0.3 from npm.
Its baked-in catalog has the old persona-maker (only find-skills).
New skills aren't visible until a release lands.
2. Even with the local CLI build, local skill sources resolve relative
paths against process.cwd() at install time. When invoked from
`/tmp/` or any non-workforce repo, `cp personas/skills/<x>.md ...`
fails because the .md files only exist in the workforce source repo.
Three of four skill installs fail with exit code 1.
The proactive-agents pattern (local/<name> source paths) works there
because both the persona AND its skill .md files are co-located in
the same user-repo. Persona-maker is a BUILT-IN shipped via npm —
that pattern doesn't carry across.
Fix: use the agentsMd path-form sidecar. The catalog generator at
`packages/workload-router/scripts/generate-personas.mjs` already
inlines sidecar .md content into agentsMdContent at build time, so
the published package ships a single bundled spec. The .md file is a
real markdown file the author can edit ergonomically; the user sees
the full content in AGENTS.md at session start with no runtime
filesystem lookups required.
Changes:
- New: personas/persona-maker.md — full operating spec including the
Relayfile mount, MCP servers, and Persona sidecar sections that were
previously split into local skill files. Same content the generator
would have inlined; consolidated into one file because cross-cwd
resolution made splitting unworkable.
- personas/persona-maker.json: replace agentsMdContent (inline) with
agentsMd (./persona-maker.md). Drop the three local/ skill entries
from skills[]; only skill.sh/find-skills remains.
- Delete personas/skills/* — content lives in persona-maker.md now.
- Regenerated packages/workload-router/src/generated/personas.ts;
agentsMdContent now 25,371 chars with all three sections inlined.
Verified: dry-run green from /tmp (non-workforce cwd) — the
cross-repo case that previously produced 3 of 4 failed installs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgantkhaliqgant changed the title feat(persona-maker): mount/MCP/sidecar guidance as local skillsfeat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecarMay 13, 2026
Ricky Schema Cascadeand others added 4 commits May 13, 2026 14:04
…m.dev
Previous iterations tried inlining everything in agentsMdContent and then
extracting to local skill .md files referenced via repo-relative paths.
The local-path approach broke cross-repo invocation because local skill
sources resolve against process.cwd() at install time, not the workforce
package install root. Confirmed live: persona-maker spawned from
/Users/khaliqgant/Projects/AgentWorkforce/relay only saw skill.sh/find-skills
in the opencode picker.
Fix: publish the three skills as prpm packages so they're installable from
any cwd via npx -y prpm install <ref>.
Package layout (personas/skills/):
- prpm.json — multi-package manifest following the
@prpm/prpm-json-best-practices-skill structure: top-level metadata
(name, version, author, license, repository, organization), plus a
packages[] with three skill entries (format: generic, subtype: skill).
- LICENSE — MIT, picked up automatically by prpm publish for all packages.
- README.md — discovery / install docs.
- persona-relayfile-mount/SKILL.md — mount field deep dive: allow-list
idiom, !web vs !web/ walker gotcha, readonlyPatterns scope, agentName
overlay, .git sandbox.
- persona-mcp-servers/SKILL.md — mcpServers spec variants, $VAR
substitution, claude/codex/opencode harness matrix, permissions.allow
pairing.
- persona-sidecars/SKILL.md — claudeMd (path) vs claudeMdContent (inline)
distinction; the silent footgun the dry-run does NOT catch.
persona-maker.json:
- skills[] now declares the three @agent-workforce/persona-* refs
alongside skill.sh/find-skills. They install via prpm at session start
and appear in the opencode Skills picker.
- agentsMd: ./persona-maker.md — slim sidecar restored, with the three
embedded sections replaced by pointers to the published skills.
Anti-goals updated to reference the new skill IDs.
Regenerated packages/workload-router/src/generated/personas.ts.
`prpm publish --dry-run` from personas/skills/: ✓ all 3 packages ready
to publish under @agent-workforce/ scope (khaliqgant ✓ as org member).
Publish runs separately (user-driven, not automated in this commit).
After publish lands on prpm.dev, `agentworkforce agent persona-maker
--dry-run` will install all four skills cleanly. Until then the dry-run
exercising the three new skills will fail at the prpm registry lookup
step — expected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…works
Published 1.0.0 with format: generic. Install via `npx -y prpm install
@agent-workforce/persona-relayfile-mount --as opencode` (the command
persona-kit emits for opencode-harness personas) errors with:
Failed to parse generic format: Unsupported source format for
conversion: generic
prpm has format converters keyed off the source format. `generic` has
no converter to `opencode` / `codex` / etc., so install fails the
moment the workforce CLI tries to materialize the skill.
Bump to 1.0.1 with format: claude. SKILL.md with YAML frontmatter is
canonically claude-flavored, and prpm knows how to convert claude →
opencode (verified by installing @agent-relay/choosing-swarm-patterns
with --as opencode: ✓ Converted from claude to opencode).
Dry-run validates clean for all three packages at 1.0.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…eneric
Verified after publish: `prpm show @agent-workforce/persona-relayfile-mount`
returns "Type: generic skill" at version 1.0.1, and `prpm install --as
opencode` still errors "Failed to parse generic format". Either the
publish of 1.0.1 happened before the format-change commit landed in the
working tree, or prpm caches format metadata at first publish — either
way, the remote tarball is still generic.
Bump to 1.0.2 with format: claude. Dry-run confirms:
Package: @agent-workforce/persona-relayfile-mount@1.0.2
Format: claude | Subtype: skill
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The prpm registry route now updates mutable manifest fields on republish
(format, subtype, description, tags, etc.), so the three skills finally
landed as format: claude. Verified end-to-end:
- `prpm show @agent-workforce/persona-relayfile-mount` reports Type:
claude skill at v1.0.3 (previously locked at generic from 1.0.0).
- `agentworkforce agent persona-maker --dry-run` from /tmp:
✓ dry-run ok: 4 skill(s) installed cleanly. All three new skills now
convert claude → opencode and materialize into .opencode/skills/ at
session start.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
khaliqgant merged commit a338122 into mainMay 13, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the persona-maker-mount-mcp-guidance branch May 13, 2026 12:55
Sign up for freeto 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.

1 participant

@khaliqgant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecar - #108

Merged
khaliqgant merged 8 commits into
mainfrom
persona-maker-mount-mcp-guidance
May 13, 2026
Merged

feat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecar#108
khaliqgant merged 8 commits into
mainfrom
persona-maker-mount-mcp-guidance

Conversation

@khaliqgant

@khaliqgantkhaliqgant commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

The persona-maker built-in was missing teaching content for mount, mcpServers, and the silent-footgun distinction between claudeMd (path) and claudeMdContent (inline). A persona authored against the existing spec hit four real failure modes:

  1. claudeMdContent: \"web-blog-content-writer.claudeMdContent.md\" — filename string written verbatim as CLAUDE.md body (dry-run green, agent boots with no spec).
  2. mount.ignoredPatterns: [\"**\", \"!./web/**\"]** breaks ! re-includes; empty mount.
  3. readonlyPatterns: [\"web/**\"] on the persona's own work directory — writes silently dropped on sync-back.
  4. model: \"claude-sonnet\" — bare alias without version, harness errors at spawn.

Changes

New filepersonas/persona-maker.md — the persona's full operating spec, including dedicated sections for Relayfile mount policy (allow-list idiom, the non-obvious !web vs !web/ walker bug, readonlyPatterns scope rule, per-agent dotfile overlay, .git sandbox behavior), MCP servers (two spec variants, \$VAR secret substitution, claude/codex/opencode support matrix, permissions.allow pairing), and Persona sidecar fields (path-vs-inline distinction with explicit "dry-run does NOT catch this" callout).

persona-maker.json:

  • Replaces inline agentsMdContent with agentsMd: \"./persona-maker.md\" (path form). The catalog generator at packages/workload-router/scripts/generate-personas.mjs inlines the .md content into the published spec at build time, so the package still ships a single bundled JSON.
  • New rules in the body: full model identifiers (claude-sonnet-4-6 not claude-sonnet).
  • Anti-goals extended with the four lessons learned plus the mount allow-list !dir (no slash) rule.

Regeneratedpackages/workload-router/src/generated/personas.ts. agentsMdContent is now 25,371 chars and contains all three sections, ready to ship.

Design history

Earlier iterations tried two paths that don't survive cross-repo invocation:

  • Inlining everything in agentsMdContent (one giant escaped string): worked but unmaintainable.
  • Extracting to three local personas/skills/*.md files referenced via local/<name> source paths (the proactive-agents pattern): worked from inside the workforce repo, failed everywhere else. Local skill sources resolve relative paths against process.cwd() at install time; the .md files don't exist in user repos, so cp fails. Reproduced from /tmp/: ✗ 3 of 4 skill(s) failed.

The proactive-agents pattern works because both the persona AND the skill files are co-located in the user's own repo. Persona-maker is a built-in shipped via npm — same pattern doesn't carry.

The agentsMd sidecar approach gets the maintainability win (editable .md file with proper markdown structure) without the cross-repo failure: the generator already inlines the sidecar at build time and the harness loads AGENTS.md from the session cwd, with no runtime filesystem lookups against unfamiliar directories.

Test plan

  • node -e \"require('./personas/persona-maker.json')\" parses; agentsMd resolved to ./persona-maker.md.
  • Catalog generator inlines: published agentsMdContent now 25,371 chars with ## Relayfile mount policy, ## MCP servers, ## Persona sidecar fields.
  • Dry-run from /tmp/ (non-workforce cwd) — the case that previously failed: ✓ dry-run ok: 1 skill(s) installed cleanly.
  • Companion fix in relayfile for the trailing-slash negation walker bug: fix(local-mount): trailing-slash negations now re-include allow-listed directories relayfile#145.

To test locally after merge

The published agentworkforce@3.0.3 on PATH won't pick this up until the next release. To test now:

```bash
cd ~/Projects/AgentWorkforce/workforce
git pull
corepack pnpm install
corepack pnpm --filter @agentworkforce/workload-router --filter @agentworkforce/cli build

From any directory:

node ~/Projects/AgentWorkforce/workforce/packages/cli/dist/cli.js agent persona-maker
```

🤖 Generated with Claude Code

persona-maker.json's AGENTS.md sidecar only listed `mount` and
`mcpServers` as optional fields without explaining when to use them,
the shape, or how harness selection is constrained by MCP support.
Authored personas needing filesystem sandboxing or MCP wiring were a
coin-flip on getting these blocks right.
- Add a `mount` section covering ignoredPatterns/readonlyPatterns
semantics, the `.{persona.id}.agentignore` overlay behavior keyed off
`agentName: persona.id`, the gitignore-negation idiom for allow-lists,
the file-scope-vs-tool-scope split from `permissions`, and the
auto-`.git` sandbox behavior.
- Add an `mcpServers` section with the two spec variants (http/sse vs
stdio), an example of each, `$VAR` substitution policy, and the
claude / codex / opencode support matrix so harness selection is
informed when MCP is required.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR externalizes the persona authoring specification from an inline agentsMdContent field in personas/persona-maker.json into a dedicated personas/persona-maker.md file. The new markdown document provides comprehensive, structured guidance for authoring a Workforce persona, covering required JSON schema, mount policy, MCP servers, sidecar fields, runtime configuration, validation workflow, built-in catalog integration, and explicit anti-goals.

Changes

Persona authoring specification

Layer / File(s)Summary
Persona JSON refactoring and schema foundation
personas/persona-maker.json, personas/persona-maker.md
The JSON file now references ./persona-maker.md instead of embedding agentsMdContent. The new guide introduces required persona JSON shape including id/intent, metadata (tags, description, skills), runtime fields (harness, model, systemPrompt, harnessSettings), and prompt authoring constraints.
Mount policy specification
personas/persona-maker.md, personas/skills/persona-relayfile-mount/SKILL.md
Specifies the mount JSON shape and policy: ignoredPatterns vs readonlyPatterns, per-agent dotfile overlays (.{id}.agentignore/.{id}.agentreadonly), gitignore-style allow-list rules with non-obvious negation requirements, .git sync behavior, and a detailed pre-handoff checklist.
MCP servers specification
personas/persona-maker.md, personas/skills/persona-mcp-servers/SKILL.md
Documents mcpServers configuration including uniform server spec, remote http/sse vs local stdio variants, $VAR/${VAR} secret substitution and unset behavior, harness support matrix, permissions pairing via mcp__* keys, and an MCP authoring checklist.
Sidecar markdown fields specification
personas/persona-maker.md, personas/skills/persona-sidecars/SKILL.md
Defines sidecar fields (claudeMd/agentsMd vs *MdContent), path vs inline semantics and the silent-failure footgun when *MdContent is used incorrectly, *MdMode options (overwrite/extend), and a sidecar authoring checklist.
Runtime, validation, and authoring workflow
personas/persona-maker.md
Lays out runtime defaults for harness, model, reasoning, and timeoutSeconds, describes skill discovery/curation and required agentworkforce agent <id> --dry-run validation checks, details persona prompt authoring steps and built-in catalog integration, lists anti-goals, and specifies the handoff contract.
Skills package manifest, README & LICENSE
personas/skills/prpm.json, personas/skills/README.md, personas/skills/LICENSE
Adds agentworkforce-persona-authoring-skills manifest registering three skills and includes README and MIT license for the skills package.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested reviewers

  • willwashburn

Poem

🐰 The spec hops free from JSON's nest,

A markdown tome emerges dressed,
Mounts and MCPs set in lines,
Sidecars, checklists, clear design,
Persona makers, now you're blessed.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title accurately summarizes the main change: adding guidance documentation for mount/MCP/sidecar features via a persona-maker.md sidecar file referenced in agentsMd.
Description check✅ PassedThe description clearly relates to the changeset, explaining the four failure modes being fixed, the new teaching content added, design decisions, and test plans.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch persona-maker-mount-mcp-guidance

Comment @coderabbitai help to get the list of available commands and usage tips.

@devin-ai-integrationdevin-ai-integrationBot 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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

…ills
The mount and MCP additions from the previous commit made agentsMdContent
even longer. Extract them — plus the silent-footgun guidance about
claudeMdContent vs claudeMd — into three local skill .md files matching
the proactive-agents skill-loading pattern. The skills install into the
session via the local source-kind, so the persona reads them as standalone
SKILL.md files in its working dir instead of carrying everything inline.
Skills:
- personas/skills/relayfile-mount.md — mount field deep dive: allow-list
idiom (/* not **, paired !dir/ + !dir/**), readonlyPatterns scope rule
(never the work dir), agentName overlay, .git sandbox behavior.
- personas/skills/persona-mcp-servers.md — mcpServers two variants
(http/sse vs stdio), $VAR substitution, claude/codex/opencode support
matrix, permissions.allow pairing.
- personas/skills/persona-sidecars.md — claudeMd (path) vs claudeMdContent
(inline) distinction; calls out that the dry-run does NOT catch a path
string mistakenly stored in *MdContent.
persona-maker.json:
- skills[] now declares the three local skills alongside skill.sh/find-skills.
- agentsMdContent trimmed: the long mount/MCP/sidecar paragraphs are
replaced with one-line skill pointers. Net length: 15985 → 15318 chars.
- Anti-goals extended with the four lessons from a recent broken persona:
filename string in *MdContent; ** as broad mount exclude; readonly on
work dir; opencode + mcpServers; bare model alias without version.
- Added 'full model identifiers' rule (claude-sonnet-4-6, not claude-sonnet).
Regenerated packages/workload-router/src/generated/personas.ts to pick up
the new skills.
Dry-run: ✓ 4 skill(s) installed cleanly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgantkhaliqgant changed the title docs(persona-maker): teach mount policy and mcpServers shapefeat(persona-maker): mount/MCP/sidecar guidance as local skillsMay 13, 2026
The "obvious" gitignore allow-list `["/*", "!web/", "!web/**"]` silently
produces an empty mount. Reproduced against relayfile's createMount:
mount root contained only CLAUDE.md, _MOUNT_README.md, and .relayfile-local-mount
— no web/.
Root cause in relayfile-local-mount/src/mount.ts isPathMatched():
return matcher.ignores(relPath) || (isDirectory && matcher.ignores(`${relPath}/`));
The OR short-circuits. For a directory `web`:
- matcher.ignores('web') → true (`/*` matches the bare name)
- matcher.ignores('web/') → false (`!web/` negates the trailing-slash form)
but this branch is never reached.
So `!web/` (slash) only counters the trailing-slash form, leaving the
bare-name check unopposed. The walker treats `web` as ignored and skips
recursion. Verified by harness:
/* + !web/ + !web/** → web (dir) reported as ignored: true (broken)
/* + !web + !web/** → web (dir) reported as ignored: false (correct)
Confirmed end-to-end against a real createMount: with `!web` the mount
root contains web/content/post.md as expected.
Updates:
- relayfile-mount.md skill: add a fourth rule explicitly calling out the
`!dir` vs `!dir/` distinction with the walker's short-circuit as the
reason, plus a "wrong / right" side-by-side. Update the checklist line.
- persona-maker.json anti-goal: replace `!dir/` reference with `!dir`
plus the reason.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitaicoderabbitaiBot 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.

🧹 Nitpick comments (1)
personas/skills/relayfile-mount.md (1)

32-33: 💤 Low value

Consider clarifying the placeholder notation.

The .{id} notation could be more explicit that it's a placeholder. For an AI agent consuming this skill, consider using .${id} or adding a concrete example like "For a persona with id: blog-writer, the dotfile would be .blog-writer.agentignore."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@personas/skills/relayfile-mount.md` around lines 32 - 33, The placeholder
notation `.{id}.agentignore` and `.{id}.agentreadonly` is ambiguous; update
these entries to use a clearer placeholder like `.${id}.agentignore` and
`.${id}.agentreadonly` or add a concrete example line (e.g., for `id:
blog-writer` show `.blog-writer.agentignore`) so readers and agents understand
that `{id}` is substituted with the persona id.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@personas/skills/relayfile-mount.md`:
- Around line 32-33: The placeholder notation `.{id}.agentignore` and
`.{id}.agentreadonly` is ambiguous; update these entries to use a clearer
placeholder like `.${id}.agentignore` and `.${id}.agentreadonly` or add a
concrete example line (e.g., for `id: blog-writer` show
`.blog-writer.agentignore`) so readers and agents understand that `{id}` is
substituted with the persona id.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 51803e8c-d30a-4235-a2b0-74028ad47bff

📥 Commits

Reviewing files that changed from the base of the PR and between dc4ec59 and bfe36f5.

⛔ Files ignored due to path filters (1)
  • packages/workload-router/src/generated/personas.ts is excluded by !**/generated/**
📒 Files selected for processing (4)
  • personas/persona-maker.json
  • personas/skills/persona-mcp-servers.md
  • personas/skills/persona-sidecars.md
  • personas/skills/relayfile-mount.md
✅ Files skipped from review due to trivial changes (2)
  • personas/skills/persona-sidecars.md
  • personas/skills/persona-mcp-servers.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • personas/persona-maker.json

The previous extraction-into-local-skills approach was broken in the
field. Reported live: persona-maker spawned from a non-workforce cwd
(e.g. ../relay) only loaded `find-skills` — the three local skills
`relayfile-mount`, `persona-mcp-servers`, `persona-sidecars` were
missing from opencode's Skills picker.
Two layered bugs:
1. The agentworkforce binary on PATH is the published 3.0.3 from npm.
Its baked-in catalog has the old persona-maker (only find-skills).
New skills aren't visible until a release lands.
2. Even with the local CLI build, local skill sources resolve relative
paths against process.cwd() at install time. When invoked from
`/tmp/` or any non-workforce repo, `cp personas/skills/<x>.md ...`
fails because the .md files only exist in the workforce source repo.
Three of four skill installs fail with exit code 1.
The proactive-agents pattern (local/<name> source paths) works there
because both the persona AND its skill .md files are co-located in
the same user-repo. Persona-maker is a BUILT-IN shipped via npm —
that pattern doesn't carry across.
Fix: use the agentsMd path-form sidecar. The catalog generator at
`packages/workload-router/scripts/generate-personas.mjs` already
inlines sidecar .md content into agentsMdContent at build time, so
the published package ships a single bundled spec. The .md file is a
real markdown file the author can edit ergonomically; the user sees
the full content in AGENTS.md at session start with no runtime
filesystem lookups required.
Changes:
- New: personas/persona-maker.md — full operating spec including the
Relayfile mount, MCP servers, and Persona sidecar sections that were
previously split into local skill files. Same content the generator
would have inlined; consolidated into one file because cross-cwd
resolution made splitting unworkable.
- personas/persona-maker.json: replace agentsMdContent (inline) with
agentsMd (./persona-maker.md). Drop the three local/ skill entries
from skills[]; only skill.sh/find-skills remains.
- Delete personas/skills/* — content lives in persona-maker.md now.
- Regenerated packages/workload-router/src/generated/personas.ts;
agentsMdContent now 25,371 chars with all three sections inlined.
Verified: dry-run green from /tmp (non-workforce cwd) — the
cross-repo case that previously produced 3 of 4 failed installs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgantkhaliqgant changed the title feat(persona-maker): mount/MCP/sidecar guidance as local skillsfeat(persona-maker): mount/MCP/sidecar guidance via agentsMd sidecarMay 13, 2026
Ricky Schema Cascadeand others added 4 commits May 13, 2026 14:04
…m.dev
Previous iterations tried inlining everything in agentsMdContent and then
extracting to local skill .md files referenced via repo-relative paths.
The local-path approach broke cross-repo invocation because local skill
sources resolve against process.cwd() at install time, not the workforce
package install root. Confirmed live: persona-maker spawned from
/Users/khaliqgant/Projects/AgentWorkforce/relay only saw skill.sh/find-skills
in the opencode picker.
Fix: publish the three skills as prpm packages so they're installable from
any cwd via npx -y prpm install <ref>.
Package layout (personas/skills/):
- prpm.json — multi-package manifest following the
@prpm/prpm-json-best-practices-skill structure: top-level metadata
(name, version, author, license, repository, organization), plus a
packages[] with three skill entries (format: generic, subtype: skill).
- LICENSE — MIT, picked up automatically by prpm publish for all packages.
- README.md — discovery / install docs.
- persona-relayfile-mount/SKILL.md — mount field deep dive: allow-list
idiom, !web vs !web/ walker gotcha, readonlyPatterns scope, agentName
overlay, .git sandbox.
- persona-mcp-servers/SKILL.md — mcpServers spec variants, $VAR
substitution, claude/codex/opencode harness matrix, permissions.allow
pairing.
- persona-sidecars/SKILL.md — claudeMd (path) vs claudeMdContent (inline)
distinction; the silent footgun the dry-run does NOT catch.
persona-maker.json:
- skills[] now declares the three @agent-workforce/persona-* refs
alongside skill.sh/find-skills. They install via prpm at session start
and appear in the opencode Skills picker.
- agentsMd: ./persona-maker.md — slim sidecar restored, with the three
embedded sections replaced by pointers to the published skills.
Anti-goals updated to reference the new skill IDs.
Regenerated packages/workload-router/src/generated/personas.ts.
`prpm publish --dry-run` from personas/skills/: ✓ all 3 packages ready
to publish under @agent-workforce/ scope (khaliqgant ✓ as org member).
Publish runs separately (user-driven, not automated in this commit).
After publish lands on prpm.dev, `agentworkforce agent persona-maker
--dry-run` will install all four skills cleanly. Until then the dry-run
exercising the three new skills will fail at the prpm registry lookup
step — expected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…works
Published 1.0.0 with format: generic. Install via `npx -y prpm install
@agent-workforce/persona-relayfile-mount --as opencode` (the command
persona-kit emits for opencode-harness personas) errors with:
Failed to parse generic format: Unsupported source format for
conversion: generic
prpm has format converters keyed off the source format. `generic` has
no converter to `opencode` / `codex` / etc., so install fails the
moment the workforce CLI tries to materialize the skill.
Bump to 1.0.1 with format: claude. SKILL.md with YAML frontmatter is
canonically claude-flavored, and prpm knows how to convert claude →
opencode (verified by installing @agent-relay/choosing-swarm-patterns
with --as opencode: ✓ Converted from claude to opencode).
Dry-run validates clean for all three packages at 1.0.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…eneric
Verified after publish: `prpm show @agent-workforce/persona-relayfile-mount`
returns "Type: generic skill" at version 1.0.1, and `prpm install --as
opencode` still errors "Failed to parse generic format". Either the
publish of 1.0.1 happened before the format-change commit landed in the
working tree, or prpm caches format metadata at first publish — either
way, the remote tarball is still generic.
Bump to 1.0.2 with format: claude. Dry-run confirms:
Package: @agent-workforce/persona-relayfile-mount@1.0.2
Format: claude | Subtype: skill
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The prpm registry route now updates mutable manifest fields on republish
(format, subtype, description, tags, etc.), so the three skills finally
landed as format: claude. Verified end-to-end:
- `prpm show @agent-workforce/persona-relayfile-mount` reports Type:
claude skill at v1.0.3 (previously locked at generic from 1.0.0).
- `agentworkforce agent persona-maker --dry-run` from /tmp:
✓ dry-run ok: 4 skill(s) installed cleanly. All three new skills now
convert claude → opencode and materialize into .opencode/skills/ at
session start.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
khaliqgant merged commit a338122 into mainMay 13, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the persona-maker-mount-mcp-guidance branch May 13, 2026 12:55
Sign up for freeto 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.

1 participant

@khaliqgant