| name | promote-hotpath |
| description | Promote a mined hotpath into a zymi pipeline — the "compile" half of the LLM-as-compiler loop. Use after hotpath-miner has produced candidates and the user picks one to turn into a reusable pipeline (e.g. "promote deploy", "compile the deploy hotpath", "let's turn this into a pipeline"). The agent distils the CONVERGED procedure out of the messy session history and drafts a safe, parameterised zymi pipeline. Triggers on: "promote <candidate>", "compile this hotpath", "make a pipeline out of X", running dossier.py, or a hotpath-miner report the user wants to act on. Pair with the zymi-skill for the actual pipeline YAML surface.
|
| metadata | {"version":"0.2-alpha","scope":"hotpath-miner"} |
promote-hotpath
Turn ONE mined candidate into a zymi pipeline. This is judgement work an
interactive agent is good at — reading messy logs, deciding what actually worked,
synthesising the clean procedure. The miner found what recurs; you distil how.
You do not execute anything against the user's live systems. You build and
validate that the pipeline loads. The user runs the first real invocation.
Preconditions
- A miner run exists:
data/classified.json. If not: zymi run hotpath_miner.
- You know the candidate (the user names it, e.g.
deploy).
- The zymi-skill is available for the
pipeline/tool YAML surface — defer to it. If it isn't installed, fall back to
the zymi docs (
zymi --help, https://github.com/metravod/zymi-core) and the
existing pipelines in this repo as the reference for the YAML shape.
Workflow
-
Assemble the dossier (deterministic grounding — do not skip and grep by hand):
python3 scripts/dossier.py <candidate>
It prints, per source session, the ordered trajectory: USER ▶ anchors, full
$ commands (heredocs included), and → result tails.
-
Distil the converged procedure — apply the distillation rubric below. This
is the whole value. Read the trajectory; find what worked; throw away the dance.
-
Draft the pipeline — apply the safety rubric below. Smallest correct thing.
-
Validate it loads: zymi pipelines lists it with no error and every
tool/agent name resolves. Do NOT run it against prod.
-
Show the user the diff and the distilled procedure. They approve, they run
the first real invocation (it will be approval-gated anyway).
Distillation rubric — extract the recipe from the chaos
- Anchor on OUTCOME, never frequency. The thrash was run many times; the
working procedure often ran once. Frequency points at the bug, not the fix.
- Find the success anchor — a
USER ▶ line confirming it worked ("работает",
"готово", "подключается", "OK") — then walk backwards to the commands that
produced it. Take the last converged attempt.
- Drop the dead-ends. Exclude: reverts / restores,
cp *.bak followed by a
rollback, "aborting", "phantom", "STILL RUNNING", panel-API probes that
returned errors, schema spelunking (PRAGMA table_info, strings, find /),
and pure debugging greps. Keep only the minimal command set on the success path.
- But keep load-bearing fallbacks. A redundant-looking
A || B guard, a retry,
or a "belt-and-suspenders" second check in the source may be compensating for an
environment quirk — don't prune it as thrash. Concrete miss: a session had
pgrep -x xray-linux-amd64 || pgrep -af xray-linux; the || branch was dropped
as noise, but -x never matches (Linux truncates the process comm to 15 chars,
so it reads xray-linux-amd6) — the fallback was the only branch that worked.
When a step has two ways of doing the same check, ask why before keeping only
one; the "extra" one often encodes a lesson the earlier you already learned.
- Newest wins. If sessions disagree, prefer the most recent session's working
path — procedures drift (schema/API changed under the user).
- No success anchor → stop. If you can't identify a run that demonstrably
worked, do NOT fabricate a procedure. Report what you see and ask the user which
run succeeded. A confidently-wrong pipeline that mutates prod is the worst outcome.
Safety rubric — the emitted pipeline
- Secrets never inline. Tokens, private keys, passwords, host IPs, panel
paths →
${env.*} from a gitignored .env. List every secret you spotted in
the dossier and tell the user to rotate anything that leaked into transcripts.
- Mutating step gated. Any step that writes prod / restarts a service / edits
a DB →
requires_approval: true and no_resume: true (so fork-resume
can't re-fire it). See zymi-skill.
- Backup before mutation. If the dossier shows a
cp db db.bak (it usually
does), keep it as the first step.
- Preflight authenticates before the gate. A non-gated preflight step must
read-only exercise the same credential and path the mutation will use — hit a
cheap authed read endpoint (
GET .../list, a SELECT 1, a whoami) and exit
non-zero unless it clearly succeeded (e.g. assert HTTP 200). A stale token,
wrong panel path, or bad host must fail here, before the human is asked to
approve and before any backup — not on the mutating step. Corollary: don't let a
preflight that only checks reachability (ssh echo OK, a DB row count) stand in
for checking authorization — the two fail differently, and the auth failure is
the one that wastes an approval and litters backups. Verifying reachability but
not the actual write-credential is the classic gap.
- Loud verify after mutation — this is the de-opt guardrail. A step that
checks the change actually took (grep the new entity in the live config) and
exits non-zero if not, so the pipeline halts instead of lying.
- Verification takes time — poll, don't sleep-once. A restart/reload/deploy is
not instant: right after it, the old process is down and the new one isn't up yet.
A single check after a fixed
sleep(N) races that window and false-negatives —
which is worse than no check, because it tells the human a good change failed and
invites a needless re-run of a mutating step. Poll the success condition to a
deadline (e.g. re-check every few seconds up to 30–60s), succeed the instant it
holds, fail only when the deadline passes. Same rule for the health signal: pick a
match that is true once the thing is actually ready (a process on its full
cmdline, an HTTP 200, a row present), not a proxy that flickers during the restart.
- Target-specifics →
inputs. Host, ids, the new client/email/name — never
hardcode. That is what makes it reusable next time.
- No fragile inline heredocs.
command_template is plain string replacement
(quoting hazards). Put the vetted script in scripts/<name>.sh / a Python
@tool and invoke it by path with args. See zymi-skill tools.md. And when the
script shells out with a secret, set it as its own statement
(TOK=…; curl -H "…$TOK"), never a command prefix (TOK=… curl -H "…$TOK")
— the prefix form expands $TOK before the assignment takes effect, silently
sending an empty value (this shipped an empty Bearer → panel 404 on the first
real run).
- Idempotency. Carry the dossier's dup-guard ("abort if email exists").
Non-negotiables
- Never inline a secret into YAML.
- Never fire the pipeline against the user's live server yourself — build +
validate-load only; the user runs the first invocation.
- Never compile a candidate whose dossier shows no converged success — escalate.
- Defer to the zymi-skill for the YAML
surface; don't reinvent it here.
Output shape when done
- The distilled procedure, in plain steps, with the dead-ends you dropped and why.
- The new pipeline + tool/script files (secrets referenced via env).
- The exact secrets the user must put in
.env (names only) and any that leaked.
- The one command the user runs to try it (approval-gated).