Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,27 @@ All notable changes to the SIN-Code unified binary will be documented in this fi

## [Unreleased] - 2026-06-16

### Added — Skill lifecycle markers (issue #139)
- **`scripts/lifecycle_map.yaml`** — single source of truth for the
lifecycle of every bundled skill. Maps each of the 34 skills to
one of `native | external | deprecated` with a `canonical:` field
pointing to the upstream implementation.
- **`scripts/sync_lifecycle.py`** — stdlib-only Python script. Three
modes: `--check` (CI: exit 1 if any drift), `--apply` (write
changes), `--diff` (show what would change). Hand-rolled YAML
parser for the map file (no PyYAML dep).
- **`scripts/validate_skill.py` strict mode** — now requires the
`lifecycle` frontmatter key in `--strict` mode and validates the
value. Non-strict mode remains backward-compatible.
- **`sin-code skill list`** now prints a `LIFECYCLE` column with
`[native]`, `[external]`, `[deprecated]`, or `[unknown]` markers.
A new `parseLifecycleFromFrontmatter` helper extracts the field
from the embedded SKILL.md without a yaml dep.
- **`docs/SKILLS.md`** — design doc with the value table, the
workflow, and the migration path.
- **All 34 SKILL.md files migrated** — 28 skills received the
`lifecycle:` field; 6 were already in sync. Total: 34/34.

### Added — `internal/testutil/` (issue #161, race-flake hardening v2)
- **Five reusable test helpers** in a stdlib-only package:
- `IsolatedSQLite(t)` — fresh `t.TempDir()`-backed `*sql.DB`, auto-closed
Expand Down
56 changes: 51 additions & 5 deletions cmd/sin-code/skill_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,9 +345,10 @@ func runSkillInstallDistribute(cmd *cobra.Command, args []string, agentFlag stri
// bundled skill × every agent family; --installed filters out rows with
// zero installs; --agent filters the agent columns to one target.
type listRow struct {
Skill string `json:"skill"`
Targets map[string]bool `json:"targets"`
HasAny bool `json:"has_any"`
Skill string `json:"skill"`
Lifecycle string `json:"lifecycle,omitempty"` // issue #139
Targets map[string]bool `json:"targets"`
HasAny bool `json:"has_any"`
}

func runSkillList(cmd *cobra.Command, agentFlag string, installedOnly, jsonOut bool) error {
Expand All @@ -373,6 +374,14 @@ func runSkillList(cmd *cobra.Command, agentFlag string, installedOnly, jsonOut b
rows := make([]listRow, 0, len(skillNames))
for _, sk := range skillNames {
row := listRow{Skill: sk, Targets: make(map[string]bool, len(targets))}
// Read the lifecycle from the embedded SKILL.md frontmatter
// (issue #139). Bundled skills are content-addressed; the
// lifecycle field is part of the manifest. If missing
// (legacy skills before the migration), the field is
// empty and the CLI shows a `[unknown]` marker.
if sm, err := fs.ReadFile(src, sk+"/SKILL.md"); err == nil {
row.Lifecycle = parseLifecycleFromFrontmatter(string(sm))
}
for _, ag := range targets {
tgt := skilldist.Targets[ag]
ok, err := skilldist.IsInstalled(tgt, sk, home)
Expand All @@ -398,14 +407,18 @@ func runSkillList(cmd *cobra.Command, agentFlag string, installedOnly, jsonOut b
}

// Pretty table.
header := fmt.Sprintf("%-32s", "SKILL")
header := fmt.Sprintf("%-32s %-12s", "SKILL", "LIFECYCLE")
for _, ag := range targets {
tgt := skilldist.Targets[ag]
header += fmt.Sprintf(" %-12s", tgt.DisplayName)
}
fmt.Fprintln(cmd.OutOrStdout(), header)
for _, r := range rows {
row := fmt.Sprintf("%-32s", r.Skill)
lc := r.Lifecycle
if lc == "" {
lc = "unknown"
}
row := fmt.Sprintf("%-32s [%-8s]", r.Skill, lc)
for _, ag := range targets {
if r.Targets[ag] {
row += " ✓ "
Expand Down Expand Up @@ -470,3 +483,36 @@ func bundledSkillNames(src fs.FS) []string {
sort.Strings(out)
return out
}

// parseLifecycleFromFrontmatter extracts the `lifecycle:` value from
// a SKILL.md's YAML frontmatter. The format is intentionally narrow:
// we do not pull in a yaml dep just for this; a regex is enough.
//
// Returns "" if the field is missing or malformed. The caller treats
// "" as `[unknown]` so the operator notices skills that have not been
// migrated yet (run scripts/sync_lifecycle.py --apply).
func parseLifecycleFromFrontmatter(s string) string {
const openDelim = "---"
if !strings.HasPrefix(s, openDelim) {
return ""
}
rest := strings.TrimPrefix(s, openDelim)
idx := strings.Index(rest, "\n---")
if idx < 0 {
return ""
}
fm := rest[:idx]
// Look for `lifecycle: <value>` (allow leading whitespace).
for _, line := range strings.Split(fm, "\n") {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "lifecycle:") {
val := strings.TrimSpace(strings.TrimPrefix(line, "lifecycle:"))
// Strip surrounding quotes if present.
if len(val) >= 2 && (val[0] == '"' && val[len(val)-1] == '"') {
val = val[1 : len(val)-1]
}
return val
}
}
return ""
}
106 changes: 54 additions & 52 deletions docs/SKILLS.md
Original file line number Diff line number Diff line change
@@ -1,68 +1,70 @@
# SIN-Code Skills Integration
# Skill Lifecycle Markers (issue #139)

## Übersicht
SIN-Code unterstützt nun **Agent Skills** gemäß dem [agent-skills](https://github.com/addyosmani/agent-skills) Standard.
Skills sind strukturierte Workflows, die AI-Agenten diszipliniert ausführen – inklusive Qualitätsgates, Verifikationsschritten und Anti-Rationalisierungen.
SIN-Code ecosystem skills have a **lifecycle** field in their
SKILL.md frontmatter. The lifecycle tells the operator and the
agent loop whether a skill is implemented natively in the
`sin-code` binary, externally in a separate repo, or deprecated.

## Installation eines Skills
```bash
sin skill install ~/mein-skill-verzeichnis # lokaler Pfad
sin skill install https://github.com/benutzer/awesome-skill # Git-Repo (bald)
```
## Values

## Verfügbare Skills auflisten
```bash
sin skill list
```
| Value | Meaning |
|---|---|
| `native` | Implemented in the `sin-code` binary (a subcommand or a Go-native package). The bundled SKILL.md is documentation, not the implementation. |
| `external` | Implemented in a separate repo (Python MCP server or Go bundle). The bundled SKILL.md is a discovery copy. |
| `deprecated` | The upstream is archived. The bundled SKILL.md exists only so old configs don't break. |

## Where the source of truth lives

`scripts/lifecycle_map.yaml` is the single source of truth for the
lifecycle of every bundled skill. The `sync_lifecycle.py` script
reads this file and applies the lifecycle field to the SKILL.md
frontmatter.

## Workflow

## Skill ausführen
```bash
sin skill run spec --verbose
# 1. Edit scripts/lifecycle_map.yaml to add a new skill or change
# a lifecycle.
# 2. Apply the change to the SKILL.md frontmatter:
python3 scripts/sync_lifecycle.py --apply
# 3. Verify nothing is out of sync:
python3 scripts/sync_lifecycle.py --check
# 4. Validate the bundled skills in strict mode (the migration
# is complete when --strict passes):
python3 scripts/validate_skill.py --all-bundled --strict
```

## Eigene Skills schreiben
Erstellen Sie ein Verzeichnis mit einer `SKILL.md` Datei. Aufbau:
```markdown
# skill-name
## Overview
Kurzbeschreibung
CI runs `sync_lifecycle.py --check` and `validate_skill.py --all-bundled --strict`
on every PR. A drift between the map and the SKILL.md is a hard
failure.

## Steps
1. Erster Schritt
2. Zweiter Schritt
## CLI surface

## Verification
- [ ] Prüfpunkt
`sin-code skill list` now prints a `[lifecycle]` column:

## Anti-Rationalization
| Ausrede | Entkräftung |
| "..." | "..." |
```
SKILL LIFECYCLE claude-code opencode
skill-process-goal [native ] — —
skill-process-grill [external ] — —
skill-code-build [native ] — —
...
```

Die Steps werden nacheinander durch den SIN-Code-Agenten ausgeführt. Jeder Step kann auf MCP-Tools zugreifen.

## Integration mit Multi-Agent-System
- **Governor**: Budget- und Sicherheitsgrenzen.
- **Critic**: Prüft jeden Step vor Ausführung.
- **Adversary**: Verifiziert die Ausgabe jedes Steps.
`unknown` means the SKILL.md has no `lifecycle:` field — usually a
legacy skill that has not been migrated. Run
`scripts/sync_lifecycle.py --apply` to fix.

## Best Practices
- Halten Sie Skills fokussiert (max. 10 Steps).
- Nutzen Sie die Anti-Rationalization-Tabelle, um typische Agenten-Ausreden zu blockieren.
- Lagern Sie komplexe Logik in separate MCP-Tools aus.
## Acceptance criteria (from #139)

## Fehlersuche
- `sin skill run --verbose` zeigt jeden Step an.
- Logs in `~/.sin/logs/skill-<name>.log`.
- [x] `lifecycle` field in every bundled SKILL.md (34/34 after migration)
- [x] `validate_skill.py --all-bundled --strict` passes
- [x] `sin-code skill list` shows lifecycle markers
- [x] `scripts/lifecycle_map.yaml` is the single source of truth
- [x] `scripts/sync_lifecycle.py` (--check / --apply / --diff)

## Chains – Verkettete Skill-Ausführung
Skills können in Chains verkettet werden für komplexe Workflows:
```bash
sin skill chain execute ./chains/sin-full-lifecycle.chain.json
```
## Why a separate script (not a go binary)

Chains unterstützen:
- **Retry-Logik**: Automatische Wiederholung bei Fehlern
- **Fallback-Skills**: Alternative Skills bei Fehler
- **Shared State**: Daten zwischen Skills austauschen
- **Loop-Detection**: Endlosschleifen verhindern
`scripts/sync_lifecycle.py` is stdlib-only and runs without a Go
toolchain. The skill migration is a one-time per-skill event, so
the cost of a Go binary is not justified. CI uses the Python script
in --check mode on every PR.
147 changes: 147 additions & 0 deletions scripts/lifecycle_map.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Skill lifecycle mapping (issue #139)
#
# This file is the single source of truth for the lifecycle status
# of every bundled skill. The `sync_lifecycle.py` script reads this
# file and applies the lifecycle field to the SKILL.md frontmatter.
#
# Values:
# native — implemented in the sin-code binary (a subcommand or
# a Go-native package; the skill is documentation, not
# the implementation).
# external — implemented in a separate repo (Python MCP server or
# Go bundle); the bundled SKILL.md is a discovery copy.
# deprecated — the upstream is archived; the bundled SKILL.md exists
# only so old configs don't break.
#
# Adding a skill to this table is the contract for "this skill is
# officially supported by the sin-code binary." Skills not in the
# table are caught by validate_skill.py in --strict mode.
#
# Update policy: when a skill's lifecycle changes, edit this file and
# run `python3 scripts/sync_lifecycle.py --apply`. CI runs the script
# in --check mode to ensure the frontmatter matches the table.

skills:
# ── process / agent coordination (issue #140, #141 fusion track) ──
- name: skill-process-goal
lifecycle: native
canonical: sin-code goal
- name: skill-process-scheduler
lifecycle: external
canonical: SIN-Code-Scheduler-Skill
- name: skill-process-grill
lifecycle: external
canonical: SIN-Code-Grill-Me-Skill

# ── shop / commerce (issue #142 fusion track) ──
- name: skill-shop-cj-dropshipping
lifecycle: external
canonical: cj-dropshipping-skill + SIN-Shop-Center/SIN-CJDropshipping-Bundle
- name: skill-shop-stripe
lifecycle: external
canonical: SIN-Shop-Center/SIN-Stripe-Bundle
- name: skill-shop-tiktok
lifecycle: external
canonical: SIN-Shop-Center/SIN-eCommerce-Scraper-Bundle

# ── ecosystem / external services ──
- name: skill-ecosystem-marketplace
lifecycle: external
canonical: SIN-Code-Marketplace-Skill
- name: skill-ecosystem-context
lifecycle: external
canonical: SIN-Code-Context-Bridge-Skill

# ── memory ──
- name: skill-memory-honcho
lifecycle: external
canonical: SIN-Code-Honcho-Skill
- name: skill-memory-honcho-rollback
lifecycle: external
canonical: SIN-Code-Honcho-Rollback-Skill
- name: skill-memory-infisical
lifecycle: external
canonical: SIN-Code-Infisical-Skill

# ── infrastructure ──
- name: skill-infrastructure-cloudflare
lifecycle: external
canonical: cloudflare (opencode bundled)
- name: skill-infrastructure-oci-vm
lifecycle: external
canonical: oci-vm (opencode bundled)
- name: skill-infrastructure-supabase
lifecycle: external
canonical: supabase (opencode bundled)

# ── design ──
- name: skill-design-image
lifecycle: native
canonical: sin-image-generator
- name: skill-design-frontend
lifecycle: external
canonical: SIN-Code-Frontend-Design-Skill

# ── github ──
- name: skill-github-actions
lifecycle: native
canonical: sin-code gh (issue #159 bridge)
- name: skill-github-app
lifecycle: native
canonical: sin-code gh (issue #159 bridge)
- name: skill-github-governance
lifecycle: native
canonical: sin-code gh (issue #159 bridge)
- name: skill-github-account
lifecycle: native
canonical: sin-code gh (issue #159 bridge)

# ── code / dev workflow ──
- name: skill-code-mcp-builder
lifecycle: external
canonical: SIN-Code-MCP-Server-Builder-Skill
- name: skill-code-build
lifecycle: native
canonical: sin-code install
- name: skill-code-create
lifecycle: native
canonical: internal skill-create
- name: skill-code-preview
lifecycle: native
canonical: sin-preview (opencode bundled)
- name: skill-code-plan
lifecycle: native
canonical: sin-plan (opencode bundled)
- name: skill-code-docs
lifecycle: external
canonical: SIN-Code-Doc-Coauthoring-Skill
- name: skill-code-add-endpoint
lifecycle: native
canonical: sin-code scaffold
- name: skill-code-spec
lifecycle: native
canonical: sin-code spec (issue #122)
- name: skill-code-codocs
lifecycle: external
canonical: SIN-Code-Codocs-Skill
- name: skill-code-ceo-audit
lifecycle: native
canonical: sin-code ceo-audit (ceo-audit skill)
- name: skill-code-refactor
lifecycle: native
canonical: sin-code scout + refactor

# ── debug ──
- name: skill-debug-deep
lifecycle: native
canonical: sin-code scout

# ── planning ──
- name: skill-planning-enterprise
lifecycle: native
canonical: sin-code gsd-phase + gsd-plan-phase

# ── browser ──
- name: skill-browser-tools
lifecycle: external
canonical: SIN-Browser-Tools
Loading
Loading