🧠 Add brain-dump docs for skill adaptation
Add exploratory and design docs for porting dirigent skills to reliquary, including: - Explore port options for the gitea skill (in-plugin vs vendored) - Document activation mechanics across Claude Code and cross-tools - Include an orchestration comparison between dirigent and reliquary approaches - Add research on glob negation and flag-file activation patterns - Create uv-detection goals and skill-engines cross-tool reports - Provide a research plan for future porting work and risk notes
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
# Porting the `gitea` skill + scripts into reliquary
|
||||
|
||||
Hands-on design for moving dirigent's `gitea` skill (which is a thin wrapper around `scripts/gitea/*.py` in the dirigent repo) into a reliquary plugin where the scripts and the skill ship as one unit.
|
||||
|
||||
## Current state in dirigent
|
||||
|
||||
```
|
||||
dirigent/
|
||||
├── .claude/skills/gitea/SKILL.md # 123 LOC — thin wrapper, points at scripts
|
||||
└── scripts/gitea/
|
||||
├── CLAUDE.md # agent reference for scripts (~127 LOC)
|
||||
├── README.md # human setup guide (~178 LOC)
|
||||
├── __init__.py
|
||||
├── client.py # 186 LOC — GiteaClient REST wrapper
|
||||
├── close_ticket.py # 39 LOC
|
||||
├── config.py # 68 LOC — env loading
|
||||
├── create_ticket.py # 115 LOC
|
||||
├── fetch_ticket.py # 113 LOC
|
||||
├── list_tickets.py # 56 LOC
|
||||
├── models.py # 66 LOC — Pydantic models
|
||||
├── post_comment.py # 69 LOC
|
||||
├── setup_labels.py # 43 LOC
|
||||
└── start_ticket.py # 163 LOC
|
||||
```
|
||||
|
||||
Total: ~919 LOC of Python + ~430 LOC of docs.
|
||||
|
||||
The skill itself does almost nothing — it tells the agent to *read* `scripts/gitea/CLAUDE.md` and *run* `uv run python -m scripts.gitea.<module>`. Everything load-bearing lives in the dirigent project root: the venv, `uv.lock`, `pyproject.toml`, and `.env`.
|
||||
|
||||
## The fundamental tension
|
||||
|
||||
The dirigent skill assumes:
|
||||
1. **The Python scripts live in the project being worked on**, importable as `scripts.gitea.*` from project root.
|
||||
2. **The project has uv set up and a `.env` with `GITEA_*` vars.**
|
||||
3. **The user is in dirigent itself** — the skill says `dirigent workpad`, references `docs/workpad/tickets/`, and the labels list (🐛 bug, ✨ feature, 📋 workpad…) is curated for dirigent.
|
||||
|
||||
To turn this into a **reusable plugin skill**, none of those assumptions hold. The scripts must live with the plugin, work from anywhere, and adapt to any project's workpad layout.
|
||||
|
||||
## Two viable port shapes
|
||||
|
||||
### Option A — Scripts ship inside the plugin (recommended)
|
||||
|
||||
```
|
||||
plugins/gitea/
|
||||
├── .claude-plugin/plugin.json
|
||||
├── README.md
|
||||
└── skills/gitea/
|
||||
├── SKILL.md
|
||||
└── scripts/
|
||||
├── __init__.py
|
||||
├── client.py
|
||||
├── config.py
|
||||
├── models.py
|
||||
├── fetch_ticket.py
|
||||
├── create_ticket.py
|
||||
├── post_comment.py
|
||||
├── start_ticket.py
|
||||
├── list_tickets.py
|
||||
├── close_ticket.py
|
||||
└── setup_labels.py
|
||||
```
|
||||
|
||||
Invocation pattern changes:
|
||||
|
||||
- Skill expands `${CLAUDE_PLUGIN_ROOT}` to locate scripts.
|
||||
- Each call becomes `uv run --no-project --with httpx --with pydantic --with python-dotenv python ${CLAUDE_PLUGIN_ROOT}/skills/gitea/scripts/fetch_ticket.py 42` — or, better, an inline-deps PEP 723 header at the top of each script so they're self-installing.
|
||||
- Env vars come from `.env` in the *current working directory* (the project the user is in), not the plugin dir. `python-dotenv` already supports this.
|
||||
- Workpad path comes from the `workpad` skill's resolution rules (env var → just recipe → `/docs/workpad`), not hardcoded.
|
||||
|
||||
**Pros:**
|
||||
- Plugin is fully self-contained — install it once, use it in any repo.
|
||||
- Versioned together with the skill markdown.
|
||||
- No requirement that the host project has uv configured.
|
||||
|
||||
**Cons:**
|
||||
- `uv run --no-project --with httpx ...` is slow on first run (env build). Mitigation: PEP 723 headers + `uv` cache make second-run startup fast.
|
||||
- The scripts must be reworked to take a workpad root as an arg (or env var) rather than hardcoding `docs/workpad/`.
|
||||
|
||||
### Option B — Scripts vendored into each project (rejected)
|
||||
|
||||
Keep the dirigent shape: ship a "scaffolder" that copies scripts into the user's repo. This is what `superpowers`-style skills sometimes do.
|
||||
|
||||
**Why reject:** updates don't propagate, every project carries duplicate code, and the scripts become "the user's code now" which makes version skew permanent.
|
||||
|
||||
## Concrete port checklist
|
||||
|
||||
If we go with Option A:
|
||||
|
||||
### Phase 1 — copy + decouple from dirigent
|
||||
1. Copy `scripts/gitea/` contents → `plugins/gitea/skills/gitea/scripts/`.
|
||||
2. Drop `__init__.py` if scripts are run as files; keep it if we want `python -m`.
|
||||
3. Add PEP 723 inline-dep blocks to each CLI entrypoint (`fetch_ticket.py`, `create_ticket.py`, etc.):
|
||||
```python
|
||||
# /// script
|
||||
# requires-python = ">=3.11"
|
||||
# dependencies = ["httpx", "pydantic>=2", "python-dotenv"]
|
||||
# ///
|
||||
```
|
||||
This makes each script runnable in isolation via `uv run script.py` without a project context.
|
||||
4. Rewrite imports: `from scripts.gitea.client import ...` → `from client import ...` (relative within the scripts/ dir). Or run as `python -m` with `PYTHONPATH` set.
|
||||
|
||||
### Phase 2 — parameterize project-specific behavior
|
||||
5. Replace hardcoded `docs/workpad/tickets/` with a CLI flag `--workpad <path>` defaulting to env var `WORKPAD_FOLDER`, defaulting to `./docs/workpad`. Honor the `workpad` skill's resolution order.
|
||||
6. Move the hardcoded label-emoji list out of `setup_labels.py` into a JSON/YAML file shipped with the plugin (`labels.default.json`) so users can override per-project.
|
||||
7. Audit any other dirigent-isms: references to "dirigent" in error messages, the README mentioning dirigent's workpad, etc.
|
||||
|
||||
### Phase 3 — rewrite the skill markdown
|
||||
8. `Step 0: Read Current Script Capabilities` currently points at `scripts/gitea/CLAUDE.md`. Replace with **inline** capability summary in the SKILL itself — the skill *is* the reference now; the scripts are an implementation detail.
|
||||
9. Replace every `uv run python -m scripts.gitea.X` example with `uv run ${CLAUDE_PLUGIN_ROOT}/skills/gitea/scripts/X.py`.
|
||||
10. Connectivity check stays — just relocate the inline `python -c` snippet's imports to whatever the new module layout is.
|
||||
11. Error-recovery table stays as-is. It's good.
|
||||
|
||||
### Phase 4 — documentation
|
||||
12. README at plugin root: install instructions + Gitea token setup. Lift most of `scripts/gitea/README.md`, drop the dirigent-specific bits.
|
||||
13. The skill markdown should be self-contained — don't make the agent open a second file unless absolutely necessary.
|
||||
|
||||
## Things to NOT do in the port
|
||||
|
||||
- **Don't keep both `CLAUDE.md` and `SKILL.md` for the scripts.** That split made sense in dirigent because the scripts had a life of their own outside the skill. Inside a plugin they don't. One file: `SKILL.md`.
|
||||
- **Don't ship Pydantic v2 + httpx as hard plugin dependencies installed in the user's project venv.** Use PEP 723 inline deps so uv builds an isolated env per invocation.
|
||||
- **Don't hardcode `closes #N` / `fixes #N` keywords** — those are Gitea behavior, not script behavior. They should stay in the skill markdown as guidance, not in code.
|
||||
- **Don't copy `setup_labels.py`'s default label set verbatim.** It's tuned for one user's taste. Externalize.
|
||||
|
||||
## Open question — sibling skill in a "mini plugin"
|
||||
|
||||
The user mentioned wanting **another skill in a custom mini plugin** that builds on this. That's not designed yet — likely candidates given the workpad ecosystem:
|
||||
|
||||
- A `gitea-workpad-flow` skill that ties together: "fetch a ticket → write plan in workpad → post plan back as comment → branch via `start_ticket`". This is workflow glue, not API access.
|
||||
- A `gitea-bulk` skill for grooming: relabel many issues, close stale ones, etc.
|
||||
- A `gitea-pr` skill if/when Gitea's PR API gets used (the current scripts only touch issues).
|
||||
|
||||
These should be a separate plugin so the core `gitea` plugin stays purely a thin API wrapper. The workflow-glue skill *depends on* the API skill but is opinionated about flow — exactly the kind of thing that should be swappable.
|
||||
|
||||
## Estimated work
|
||||
|
||||
| Phase | Effort | Risk |
|
||||
|---|---|---|
|
||||
| Copy + PEP 723 conversion | ~1h | Low — mechanical |
|
||||
| Parameterize workpad path + labels | ~1-2h | Medium — touches 4-5 files |
|
||||
| Skill markdown rewrite | ~30min | Low |
|
||||
| README + plugin manifest | ~20min | Low |
|
||||
| Manual end-to-end test (real Gitea + new project) | ~1h | This is where the bugs are |
|
||||
|
||||
Total: **half a day of focused work** for a complete port. The `start_ticket` flow is the most likely to surface issues because it touches git state, the workpad, and the API in one call.
|
||||
Reference in New Issue
Block a user