Skip to content

feat(persona-registry): warn when an agent's persona.json is stale - #321

Open
willwashburn wants to merge 5 commits into
mainfrom
feat/warn-stale-agent-persona
Open

feat(persona-registry): warn when an agent's persona.json is stale#321
willwashburn wants to merge 5 commits into
mainfrom
feat/warn-stale-agent-persona

Conversation

@willwashburn

@willwashburn willwashburn commented Aug 20, 2026

Copy link
Copy Markdown
Member

An agent directory whose persona.json is older than its persona.ts loads the compiled spec with none of the edits sitting in the authoring file. Nothing about the result looks wrong — the persona appears in list, resolves in agent, deploys — it is simply the previous version.

#316 warned about a persona that was never compiled. This covers the quieter case: one that was compiled once and has drifted.

$ agentworkforce list        # in ../sales, after editing persona.ts
warning: [cwd:agents] proposal-agent: persona.json is older than persona.ts, so this
persona is loading without the latest edits; re-run `agentworkforce persona compile
.../agents/proposal-agent/persona.ts`.

PERSONA         SOURCE      HARNESS  MODEL
proposal-agent  cwd:agents  claude   claude-opus-4-8

The persona is still served. Dropping it would turn a forgotten compile into a missing persona — a worse failure than an out-of-date one, and one that would break deploy and agent rather than just informing them.

Verification

Exercised against the real ../sales checkout: warns after touching persona.ts, clears after persona compile. Two new tests backdate the artifact with utimesSync rather than sleeping, covering both orderings. local-personas suite passes (53).

Semver: patch — a new diagnostic on an existing path, no resolution behavior changes.

🤖 Generated with Claude Code

Review in cubic

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1dc92a46-f9a9-46cd-a4ad-9a12ef9625f8

📥 Commits

Reviewing files that changed from the base of the PR and between 558784d and 946f52a.

📒 Files selected for processing (2)
  • packages/cli/src/local-personas.test.ts
  • packages/persona-registry/src/local-personas.ts

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Nested persona loading now compares authored source and compiled artifact modification times. Stale compiled personas remain available with a warning. Missing compiled personas remain skipped. CLI tests cover stale and current artifacts.

Changes

Persona mtime loading

Layer / File(s) Summary
Mtime-aware nested persona loading
packages/persona-registry/src/local-personas.ts, packages/cli/src/local-personas.test.ts
The loader detects stale compiled personas by comparing modification times. It warns when persona.json is older than the authored source and still loads the compiled spec. It retains the missing-compile warning and skips entries without compiled files. Tests cover stale and current artifacts.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 946f5

This change adds a warning for stale persona artifacts while preserving existing loading behavior; no actionable merge-blocking risk remains.

Suggested reviewers: khaliqgant

Poem

I thump my paws; the times now align,
Old compiled leaves receive a sign.
Fresh personas hop in clear,
Missing ones stay out of here.
— A careful rabbit 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the new stale persona.json warning.
Description check ✅ Passed The description accurately explains the stale artifact warning, preserved loading behavior, tests, and user remediation.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/warn-stale-agent-persona

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 946f52af9e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +423 to +425
const authored = NESTED_PERSONA_SOURCE_FILENAMES.map((file) => join(sourceDir, file)).find(
(candidate) => fileMtimeMs(candidate) !== undefined
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Inspect every authoring candidate for staleness

When an agent directory contains multiple supported authoring files—for example, an old persona.ts remains after development moves to persona.js—this fixed-order find() always selects the TypeScript file. If persona.json is newer than that old file but older than the actively edited JavaScript file, the stale persona loads without any warning. Compare all recognized sources and use the newest modification time (and its path) for the diagnostic.

Useful? React with 👍 / 👎.

@cubic-dev-ai cubic-dev-ai Bot 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.

All reported issues were addressed across 2 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/persona-registry/src/local-personas.ts Outdated
willwashburn and others added 2 commits August 20, 2026 12:53
An agent driven by its `onEvent` entry has no interactive launch to configure,
so `harness`, `model`, and `systemPrompt` — already optional on `PersonaSpec` —
are optional here too. Requiring them kept exactly the agents the `agents/`
directory was added for out of the registry, reporting a valid deployable
persona as malformed.

`onEvent` and `cloud` now survive parse and merge. An overlay that tweaks env no
longer strips the handler entry that makes its base deployable, so the merged
spec is a complete agent rather than a partial one.

`harnessSettings` stays required: `PersonaSpec` types it non-optional, and
`reasoning`/`timeoutSeconds` have no defensible default to invent on a
persona's behalf.

`onEvent` is validated as a relative path that cannot escape the agent
directory, matching the sidecar rule.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Hand-rolling the guard drifted from persona-kit twice over. It validated the
raw string and stored a trimmed copy, so `" ../x/agent.ts "` cleared the `..`
check as the segment `" .."` and escaped the agent directory once trimmed. And
it never checked the handler extension, so `onEvent: "README.md"` counted as a
handler and skipped the interactive fields the persona never declared.

`parseOnEvent` owns both rules and returns the exact string it validated, so
the stored value cannot differ from the one that passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@willwashburn
willwashburn force-pushed the feat/warn-stale-agent-persona branch from d77be7d to 7303cc5 Compare August 20, 2026 17:18
@willwashburn
willwashburn changed the base branch from main to feat/registry-handler-personas August 20, 2026 17:18
@willwashburn

Copy link
Copy Markdown
Member Author

Rebased onto #323 and retargeted there, so this shows only its own diff and merges without a conflict.

Merge order: #318#323#321#322. GitHub retargets each to main automatically as the one below it lands.

Worth knowing why: left on main, #321 and #322 each collided with #323 in local-personas.test.ts, and the collision was not the harmless kind. Git factored the shared trailing });\n}); out of both sides, so accepting both halves produced a test truncated mid-body that would not compile — a reviewer taking "keep both" at face value would have merged broken code. Resolved once here instead.

Full stack verified: 65 tests in local-personas, 322 across the CLI suite.

willwashburn and others added 3 commits August 20, 2026 13:24
Order matters in both directions. Validating the raw string and storing a
trimmed copy let `" ../x/agent.ts "` clear the `..` check as the segment `" .."`
and escape once trimmed. Validating without trimming stored `" ./agent.ts"`,
which passes every check and then resolves against a directory named `" ."` at
deploy.

Trimming before `parseOnEvent` makes the validated value and the stored value
the same string.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
An agent directory whose `persona.json` is older than its `persona.ts` loads
the compiled spec with none of the edits sitting in the authoring file, and
nothing about the result looks wrong. #316 warned about a persona that was
never compiled; this covers the quieter case where it was compiled once.

The persona is still served. Dropping it would turn a forgotten compile into a
missing persona, which is a worse failure than an out-of-date one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… file

A directory that still carries an abandoned `persona.ts` after development
moved to `persona.js` was measured against the file nobody edits, so a
`persona.json` newer than the dead source but older than the live one read as
fresh.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@willwashburn
willwashburn force-pushed the feat/warn-stale-agent-persona branch from 7303cc5 to 3425fa1 Compare August 20, 2026 17:26
@willwashburn
willwashburn changed the base branch from feat/registry-handler-personas to main August 20, 2026 17:30
@willwashburn willwashburn reopened this Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant