Files
opc-skills/README.md
salvacybersec 44daf2b969 feat: feynman target + interactive target picker + fzf preview fix
- Add feynman as third target (~/.feynman/agent/skills) alongside opencode
  and claude. Default targets now: opencode,claude,feynman.
- Fix fzf {} preview shell-escape bug: {} in fzf is shell-escaped (wrapped
  in single quotes), so "$PARKED/{}/SKILL.md" embedded literal quotes into
  the path and broke preview. Switched to "$PARKED"/{}/SKILL.md (variable
  quoted, {} unquoted) so bash concatenation yields a clean path.
- pick: after skill multi-select, prompt target picker (all / opencode /
  claude / feynman, TAB for multi). ENTER on highlighted "all" = all three.
- disable-pick: rewritten to show union of actives across all 3 targets
  with [oc,cl,fy] indicators, then target picker for which to disable from.
- cmd_status: 3-target output with all-three intersection counter.
- reindex: tracks per-target active arrays for all 3.
- New env vars: OPC_FEYNMAN_ACTIVE.
2026-05-01 13:13:55 +03:00

140 lines
7.0 KiB
Markdown

# opc-skills
**Multi-target** skill manager for **opencode** + **Claude Code** + **Feynman**. Single source-of-truth (parked archive in the personas repo), per-target lazy activation. Default operations target all three platforms; an interactive target-picker prompts when picking via fzf.
## Why
opencode (≥1.14) auto-scans `~/.claude/skills/` as well as its own `~/.config/opencode/skills/` — so a 1000-skill Claude Code archive ends up bloating the opencode prompt. Feynman has its own `~/.feynman/agent/skills/`. opc-skills inverts this: keep all three target dirs *empty by default*, copy individual skills into them on demand.
For full agent / skill / persona generation across multiple AI platforms, see the upstream [`personas`](https://gitea.taygun.net.tr/salvacybersec/personas) repo.
## Install
```bash
ln -s ~/Documents/opc-skills/bin/opc-skills ~/.local/bin/opc-skills
```
Ensure `~/.local/bin` is on your `PATH`.
## Layout it expects
```
~/Documents/personas/skills-archive/ # full catalog — single source-of-truth
<skill-name>/SKILL.md
INDEX.json
INDEX.md
~/.config/opencode/skills/ # currently-enabled (opencode target)
<skill-name>/SKILL.md
~/.claude/skills/ # currently-enabled (claude target)
<skill-name>/SKILL.md
~/.feynman/agent/skills/ # currently-enabled (feynman target)
<skill-name>/SKILL.md
```
(`~/Documents/opencode-skills-parked` is symlinked to `personas/skills-archive` for backward-compat.)
Override via env:
- `OPC_PARKED` — parked catalog root (default `~/Documents/personas/skills-archive`)
- `OPC_ACTIVE` — opencode active dir (default `~/.config/opencode/skills`)
- `OPC_CLAUDE_ACTIVE` — claude active dir (default `~/.claude/skills`)
- `OPC_FEYNMAN_ACTIVE` — feynman active dir (default `~/.feynman/agent/skills`)
- `OPC_TARGETS` — comma-separated default targets (default `opencode,claude,feynman`)
## Targets
`enable`, `disable`, and `disable-all` accept `--target` / `-t`:
| flag | meaning |
|---|---|
| `--target opencode` | only `~/.config/opencode/skills/` |
| `--target claude` | only `~/.claude/skills/` |
| `--target feynman` | only `~/.feynman/agent/skills/` |
| `--target all` | all three |
| `--target both` | legacy `opencode,claude` (no feynman) |
| `--target opencode,feynman` | comma-separated subset |
When omitted, the default is taken from `OPC_TARGETS` (default `opencode,claude,feynman`).
## Commands
### Inspection
```
opc-skills status # parked + per-target active counts (3 targets)
opc-skills list {active|parked|all} # skill folder names
opc-skills categories # verb-prefix counts (performing, detecting, ...)
opc-skills domains # frontmatter `domain:` distribution
opc-skills subdomains # frontmatter `subdomain:` distribution
opc-skills tags # frontmatter `tags:` distribution
```
### Single-skill operations
```
opc-skills enable [--target T] <folder> # copy parked → active in selected targets
opc-skills disable [--target T] <folder> # remove from active in selected targets
opc-skills disable-all [--target T] [-y|--yes] # disable every active skill across targets
```
### Bulk by axis
```
opc-skills enable-category <prefix> # fzf multi-pick within a verb-prefix
opc-skills disable-category <prefix>
opc-skills enable-domain <domain> # bulk by frontmatter domain (eg. cybersecurity)
opc-skills disable-domain <domain>
opc-skills enable-subdomain <subdomain> # bulk by subdomain (eg. malware-analysis)
opc-skills disable-subdomain <subdomain>
opc-skills enable-tag [--all] <tag>... # bulk by tags (default: any; --all: intersection)
opc-skills disable-tag [--all] <tag>...
```
### Interactive / search
```
opc-skills pick # fzf: category → multi-select skills → target picker → enable
opc-skills disable-pick # fzf: union-of-actives → category → multi-select → target picker → disable
opc-skills search [query] # fzf fuzzy over name+description (enables on selection)
opc-skills disable-search [query] # fzf over ACTIVE only (disables on selection)
opc-skills reindex # rebuild INDEX.json / INDEX.md
```
#### `pick` flow
1. Choose a verb-prefix category (`performing`, `detecting`, …)
2. fzf shows skills in that category — `TAB` toggles, `ENTER` confirms
3. **Target picker** appears: `all` / `opencode` / `claude` / `feynman``TAB` for multi-select; `ENTER` on highlighted `all` (default) sends to all three
4. Selected skills are enabled in the chosen target(s)
#### `disable-pick` flow
Now multi-target aware: lists the **union of all active skills across the three targets**, with each entry annotated `[oc,cl,fy]` showing where it's currently active. After multi-select, the same target picker decides which target(s) to remove from.
`fzf` is required for the interactive commands; `jq` for the bulk-by-axis commands; `python3` (with optional `PyYAML`) for `reindex`.
### INDEX schema
`reindex` parses each `SKILL.md` frontmatter and emits records with: `folder`, `name`, `description`, `domain`, `subdomain`, `tags[]`, `active[]` (per-target list — `opencode`/`claude`/`feynman`), `status`. `enable` / `disable` perform an incremental status update on `INDEX.json` so `enable-domain` / `disable-tag` etc. stay accurate without a full reindex.
## Shared reference files
Some skills reference sibling files via `../<name>.md` (e.g. the 20 Feynman research skills use `../_platform-mapping.md` for cross-platform tool mapping). `opc-skills enable` auto-syncs any such files from PARKED → ACTIVE in **all three targets** so the relative references keep resolving.
Currently synced:
- `_platform-mapping.md` — Feynman-skills cross-platform subagent/scheduling/persistence mapping
If you add new shared-reference files at the PARKED root, extend `sync_shared_refs_to_targets()` in `bin/opc-skills`.
## Implementation notes
- `fzf` placeholder `{}` is shell-escaped automatically — preview commands use `"$PARKED"/{}/SKILL.md` (variable quoted, `{}` unquoted) so bash concatenation produces a clean path. Wrapping `{}` in extra quotes (`"$PARKED/{}/SKILL.md"`) embeds fzf's escape literals into the path and breaks preview.
## Known interaction
The `personas` repo's `build.py --install opencode` currently wipes and repopulates `~/.config/opencode/skills/` as part of installation, which destroys the active set curated here. Use `opc-skills` *after* any personas install, or skip the skills half of `build.py` installs.
`build.py --install opencode` and `build.py --install claude-skills` both emit `_platform-mapping.md` at the skills-root alongside the 20 Feynman skills (`deep-research`, `literature-review`, `paper-code-audit`, `peer-review`, `paper-writing`, `replication`, `source-comparison`, `summarize`, `alpha-research`, `eli5`, `autoresearch`, `docker`, `modal-compute`, `runpod-compute`, `session-log`, `session-search`, `jobs`, `watch`, `preview`, `contributing`).