Skill Lifecycle Skill
Trigger
Use this skill when:
- Modifying skill publish, review, or unpublish flows
- Adding or changing skill/version status fields
- Working on search, detail pages, or listing pages that show skill state
- Implementing governance actions (hide, yank, archive)
- Adding new state transitions or permission checks
State Model
Skill Container States
Enum SkillStatus (domain/skill/SkillStatus.java):
| Value |
Meaning |
ACTIVE |
Skill is operational and can have versions published |
HIDDEN |
Skill hidden by platform governance (design doc says prefer boolean hidden flag instead) |
ARCHIVED |
Skill archived by owner/namespace admin, cannot publish new versions |
Design-vs-code note: docs/14-skill-lifecycle.md specifies hidden should be a governance
overlay (boolean flag) rather than a lifecycle enum state. The current code still defines
SkillStatus.HIDDEN. New code should use the skill.hidden boolean field, not the enum value.
SkillVersion States
Enum SkillVersionStatus (domain/skill/SkillVersionStatus.java):
| Value |
Meaning |
DRAFT |
Non-public draft, can resubmit or delete |
SCANNING |
Undergoing security scan |
SCAN_FAILED |
Security scan failed |
UPLOADED |
Uploaded but not yet submitted for review (or withdrawn from review) |
PENDING_REVIEW |
Frozen pending reviewer action |
PUBLISHED |
Currently distributable |
REJECTED |
Review denied, retained |
YANKED |
Was published, withdrawn from distribution |
ReviewTask States
Enum ReviewTaskStatus (domain/review/ReviewTaskStatus.java):
| Value |
Meaning |
PENDING |
Awaiting reviewer |
APPROVED |
Reviewer approved |
REJECTED |
Reviewer rejected |
Visibility Model
Enum SkillVisibility (used in SkillPublishService):
| Value |
Publish Path |
PUBLIC |
Creates PENDING_REVIEW version, review task, security scan |
NAMESPACE_ONLY |
Same as PUBLIC but limited visibility scope |
PRIVATE |
Goes directly to UPLOADED status, no review task |
SUPER_ADMIN role bypasses review — versions go directly to PUBLISHED.
Latest Version Pointer
Skill.latestVersionId is only the latest published pointer:
- Can only point to a
PUBLISHED version
- May be
null if no published version exists
latest tag auto-follows this pointer (read-only)
- When yanking: recalculates to newest remaining
PUBLISHED version, or null
Key Transitions
| Action |
From |
To |
Notes |
Source |
| First upload (PUBLIC/NAMESPACE_ONLY) |
— |
PENDING_REVIEW |
Review task created |
SkillPublishService |
| First upload (SUPER_ADMIN) |
— |
PUBLISHED |
Direct publish, SkillPublishedEvent emitted |
SkillPublishService |
| First upload (PRIVATE) |
— |
UPLOADED |
No review task, latestVersionId updated |
SkillPublishService |
| Review approve |
PENDING_REVIEW |
PUBLISHED |
Updates latestVersionId |
Review workflow |
| Review reject |
PENDING_REVIEW |
REJECTED |
Version retained |
Review workflow |
| Withdraw review |
PENDING_REVIEW |
UPLOADED |
Deletes pending ReviewTask |
SkillGovernanceService.withdrawPendingVersion |
| Yank |
PUBLISHED |
YANKED |
Recalculates latestVersionId |
SkillGovernanceService.yankVersion |
| Hide |
— |
hidden=true |
Independent overlay |
SkillGovernanceService.hideSkill |
| Restore |
— |
hidden=false |
Independent overlay |
SkillGovernanceService.unhideSkill |
| Archive |
ACTIVE |
ARCHIVED |
SkillStatusChangedEvent emitted |
SkillGovernanceService.archiveSkill |
| Unarchive |
ARCHIVED |
ACTIVE |
SkillStatusChangedEvent emitted |
SkillGovernanceService.unarchiveSkill |
| New publish (existing pending) |
PENDING_REVIEW |
UPLOADED |
Auto-withdraw + delete review task |
SkillPublishService |
| Delete version |
DRAFT/REJECTED/SCAN_FAILED/UPLOADED |
— |
Last version protected |
SkillGovernanceService.deleteVersion |
Yank Pointer Recalculation
When yanking the current latestVersionId (SkillGovernanceService):
- Query all remaining
PUBLISHED versions for the skill
- Sort by
publishedAt DESC, then createdAt DESC, then id DESC
- Point
latestVersionId to the top result, or null if none remain
Lifecycle Projection
Read models (detail, my-skills, favorites, search) use *QueryRepository patterns:
headlineVersion — Main display version for the page
publishedVersion — Latest published version
ownerPreviewVersion — Pending review version (visible to owner/namespace admin)
resolutionMode — PUBLISHED, OWNER_PREVIEW, or NONE
Public browsing, install, download, search only use publishedVersion.
Permission Boundaries
| Action |
Who |
| Withdraw review |
Submitter only |
| Delete version |
Owner or namespace admin, only DRAFT/REJECTED/SCAN_FAILED/UPLOADED |
| Archive/unarchive |
Owner or namespace admin (ADMIN or OWNER role) |
| Hide/restore |
Platform governance (no permission check in code) |
| Yank |
Platform governance (no permission check in code) |
| Publish PUBLIC skill |
Namespace member (or SUPER_ADMIN) |
| Publish PRIVATE skill |
Namespace member (or SUPER_ADMIN) |
Delete Version Constraints
SkillGovernanceService.deleteVersion enforces:
- Only
DRAFT, REJECTED, SCAN_FAILED, or UPLOADED versions can be deleted
- Cannot delete the last remaining version of a skill
- Deletes associated storage keys (individual files +
bundle.zip)
- Deletes associated security scan records
- Updates
latestVersionId if the deleted version was the pointer
- Storage deletion happens after transaction commit with compensation recording
Domain Events
| Event |
When Emitted |
SkillStatusChangedEvent |
Archive or unarchive |
SkillPublishedEvent |
SUPER_ADMIN direct publish |
SkillVersionYankedEvent |
Yank action |
ReviewSubmittedEvent |
Create review task for PUBLIC/NAMESPACE_ONLY |
Common Pitfalls
- Setting
SkillStatus.HIDDEN directly — use skill.setHidden(true) via SkillGovernanceService instead
- Forgetting to recalculate
latestVersionId after yank or version deletion
- Not auto-withdrawing pending versions when publishing a new version
- Missing the
confirmWarnings two-step publish flow (warnings require explicit confirmation)
- Assuming all publish flows create review tasks —
PRIVATE visibility skips review
1---2name: skill-lifecycle3description: The authoritative skill lifecycle state model including container states, version states, review workflow states, visibility overlay, and governance actions. Ensures agents don't introduce invalid states or transitions.4license: Apache-2.05---67# Skill Lifecycle Skill89## Trigger1011Use this skill when:12- Modifying skill publish, review, or unpublish flows13- Adding or changing skill/version status fields14- Working on search, detail pages, or listing pages that show skill state15- Implementing governance actions (hide, yank, archive)16- Adding new state transitions or permission checks1718## State Model1920### Skill Container States2122Enum `SkillStatus` (`domain/skill/SkillStatus.java`):2324| Value | Meaning |25|-------|---------|26| `ACTIVE` | Skill is operational and can have versions published |27| `HIDDEN` | Skill hidden by platform governance (design doc says prefer boolean `hidden` flag instead) |28| `ARCHIVED` | Skill archived by owner/namespace admin, cannot publish new versions |2930**Design-vs-code note**: `docs/14-skill-lifecycle.md` specifies `hidden` should be a governance31overlay (boolean flag) rather than a lifecycle enum state. The current code still defines32`SkillStatus.HIDDEN`. New code should use the `skill.hidden` boolean field, not the enum value.3334### SkillVersion States3536Enum `SkillVersionStatus` (`domain/skill/SkillVersionStatus.java`):3738| Value | Meaning |39|-------|---------|40| `DRAFT` | Non-public draft, can resubmit or delete |41| `SCANNING` | Undergoing security scan |42| `SCAN_FAILED` | Security scan failed |43| `UPLOADED` | Uploaded but not yet submitted for review (or withdrawn from review) |44| `PENDING_REVIEW` | Frozen pending reviewer action |45| `PUBLISHED` | Currently distributable |46| `REJECTED` | Review denied, retained |47| `YANKED` | Was published, withdrawn from distribution |4849### ReviewTask States5051Enum `ReviewTaskStatus` (`domain/review/ReviewTaskStatus.java`):5253| Value | Meaning |54|-------|---------|55| `PENDING` | Awaiting reviewer |56| `APPROVED` | Reviewer approved |57| `REJECTED` | Reviewer rejected |5859### Visibility Model6061Enum `SkillVisibility` (used in `SkillPublishService`):6263| Value | Publish Path |64|-------|-------------|65| `PUBLIC` | Creates `PENDING_REVIEW` version, review task, security scan |66| `NAMESPACE_ONLY` | Same as PUBLIC but limited visibility scope |67| `PRIVATE` | Goes directly to `UPLOADED` status, no review task |6869`SUPER_ADMIN` role bypasses review — versions go directly to `PUBLISHED`.7071### Latest Version Pointer7273`Skill.latestVersionId` is **only** the latest published pointer:74- Can only point to a `PUBLISHED` version75- May be `null` if no published version exists76- `latest` tag auto-follows this pointer (read-only)77- When yanking: recalculates to newest remaining `PUBLISHED` version, or `null`7879### Key Transitions8081| Action | From | To | Notes | Source |82|--------|------|-----|-------|--------|83| First upload (PUBLIC/NAMESPACE_ONLY) | — | `PENDING_REVIEW` | Review task created | `SkillPublishService` |84| First upload (SUPER_ADMIN) | — | `PUBLISHED` | Direct publish, `SkillPublishedEvent` emitted | `SkillPublishService` |85| First upload (PRIVATE) | — | `UPLOADED` | No review task, `latestVersionId` updated | `SkillPublishService` |86| Review approve | `PENDING_REVIEW` | `PUBLISHED` | Updates `latestVersionId` | Review workflow |87| Review reject | `PENDING_REVIEW` | `REJECTED` | Version retained | Review workflow |88| Withdraw review | `PENDING_REVIEW` | `UPLOADED` | Deletes pending `ReviewTask` | `SkillGovernanceService.withdrawPendingVersion` |89| Yank | `PUBLISHED` | `YANKED` | Recalculates `latestVersionId` | `SkillGovernanceService.yankVersion` |90| Hide | — | `hidden=true` | Independent overlay | `SkillGovernanceService.hideSkill` |91| Restore | — | `hidden=false` | Independent overlay | `SkillGovernanceService.unhideSkill` |92| Archive | `ACTIVE` | `ARCHIVED` | `SkillStatusChangedEvent` emitted | `SkillGovernanceService.archiveSkill` |93| Unarchive | `ARCHIVED` | `ACTIVE` | `SkillStatusChangedEvent` emitted | `SkillGovernanceService.unarchiveSkill` |94| New publish (existing pending) | `PENDING_REVIEW` | `UPLOADED` | Auto-withdraw + delete review task | `SkillPublishService` |95| Delete version | `DRAFT`/`REJECTED`/`SCAN_FAILED`/`UPLOADED` | — | Last version protected | `SkillGovernanceService.deleteVersion` |9697### Yank Pointer Recalculation9899When yanking the current `latestVersionId` (`SkillGovernanceService`):1001. Query all remaining `PUBLISHED` versions for the skill1012. Sort by `publishedAt` DESC, then `createdAt` DESC, then `id` DESC1023. Point `latestVersionId` to the top result, or `null` if none remain103104### Lifecycle Projection105106Read models (detail, my-skills, favorites, search) use `*QueryRepository` patterns:107- `headlineVersion` — Main display version for the page108- `publishedVersion` — Latest published version109- `ownerPreviewVersion` — Pending review version (visible to owner/namespace admin)110- `resolutionMode` — `PUBLISHED`, `OWNER_PREVIEW`, or `NONE`111112**Public browsing, install, download, search only use `publishedVersion`.**113114### Permission Boundaries115116| Action | Who |117|--------|-----|118| Withdraw review | Submitter only |119| Delete version | Owner or namespace admin, only `DRAFT`/`REJECTED`/`SCAN_FAILED`/`UPLOADED` |120| Archive/unarchive | Owner or namespace admin (`ADMIN` or `OWNER` role) |121| Hide/restore | Platform governance (no permission check in code) |122| Yank | Platform governance (no permission check in code) |123| Publish PUBLIC skill | Namespace member (or `SUPER_ADMIN`) |124| Publish PRIVATE skill | Namespace member (or `SUPER_ADMIN`) |125126### Delete Version Constraints127128`SkillGovernanceService.deleteVersion` enforces:129- Only `DRAFT`, `REJECTED`, `SCAN_FAILED`, or `UPLOADED` versions can be deleted130- Cannot delete the last remaining version of a skill131- Deletes associated storage keys (individual files + `bundle.zip`)132- Deletes associated security scan records133- Updates `latestVersionId` if the deleted version was the pointer134- Storage deletion happens after transaction commit with compensation recording135136### Domain Events137138| Event | When Emitted |139|-------|-------------|140| `SkillStatusChangedEvent` | Archive or unarchive |141| `SkillPublishedEvent` | SUPER_ADMIN direct publish |142| `SkillVersionYankedEvent` | Yank action |143| `ReviewSubmittedEvent` | Create review task for PUBLIC/NAMESPACE_ONLY |144145### Common Pitfalls146147- Setting `SkillStatus.HIDDEN` directly — use `skill.setHidden(true)` via `SkillGovernanceService` instead148- Forgetting to recalculate `latestVersionId` after yank or version deletion149- Not auto-withdrawing pending versions when publishing a new version150- Missing the `confirmWarnings` two-step publish flow (warnings require explicit confirmation)151- Assuming all publish flows create review tasks — `PRIVATE` visibility skips review