| name | init-harness |
| description | Use when the user wants to scaffold a new research-discussion harness: a private GitHub repo wired to a Zulip stream, with .knowledge for papers and a Makefile for the bridge. Triggers on create a new harness, scaffold a harness, init harness for a topic, /init-harness, or set up a harness like qec.harness for another topic. Self-contained: bundles the canonical Makefile, CLAUDE.md template, and a thin project-level onboard skill that wires up the zlp-harness plugin; does not depend on any source repo. |
init-harness
When to use
- The user wants a brand-new
<topic>.harness repo modelled on the proven layout: Makefile + CLAUDE.md + .knowledge/ + Zulip bridge + a thin project-level onboard skill that delegates to the zlp-harness plugin.
- Trigger phrases: "create a new harness for ", "scaffold a harness", "init harness", "/init-harness", "set up a harness like qec.harness for ", "bootstrap the .harness repo".
Do NOT use when:
- The user already has a harness and just needs their machine wired up — that's the plugin's
zlp-onboard skill, which the harness's project-level onboard chains into.
- The user only needs a Zulip stream and no repo —
zlp send directly is enough.
- The user wants to add a paper draft (LaTeX) to an existing harness — different workflow; the
.gitignore already has the LaTeX entries set up but no scaffolding for main.tex exists yet.
What gets scaffolded
<topic>.harness/
Makefile # zulip-* targets + zulip-config; ZULIP_STREAM/ZULIP_SITE/WORKSPACE substituted
CLAUDE.md # repo conventions for future agent sessions
README.md # single-prompt onboarding instruction
AGENTS.md # @CLAUDE.md
.gitignore # LaTeX + .knowledge/.raw + .claude/settings.local
.knowledge/
INDEX.md # placeholder, overwritten on first download-ref run
.claude/skills/onboard/SKILL.md # thin two-phase: enable plugin → delegate to zlp-harness:zlp-onboard
Personal Zulip state — credentials, archived messages, cursor state, drafts — never lands in the repo. It all lives in the global workspace directory printed by make zulip-config as ZULIP_WORKSPACE_DIR_DEFAULT (one per Zulip server, shared across every harness on that server). The repo working tree only holds syncable harness configuration.
The zlp-onboard, download-ref, zulip-reply, and zlp-advisor skills are not bundled per-repo — they are provided by the zlp-harness plugin. The only skill bundled into each harness is the project-level onboard, which exists to install/enable the plugin on a collaborator's first run and then delegate.
All scaffold templates are bundled inside this skill at templates/. The skill does not read from any other repo — it is a closed unit.
Inputs (collect once, up front)
Bundle the questions into one user prompt — don't ping per-field.
| Input | Default | Notes |
|---|
topic | (required) | lowercase, hyphenated slug. Examples: qec, attention-solids, llm. Used in repo / stream / file paths. |
target-dir | (required) | Absolute path or user-expanded path for the new <topic>.harness checkout. Must be empty or non-existent (the helper refuses non-empty unless --force). |
zulip-stream | project-<topic> | the stream the bridge will target. Must already exist on Zulip — created via the web UI by an admin. |
zulip-site | https://zulip.hkust-gz.edu.cn | the Zulip server URL the harness uses. Override for non-hkust-gz sites (e.g. https://quantum-info.zulipchat.com). |
workspace | derived from zulip-site | Zulip workspace slug — names the global workspace directory printed by make zulip-config. Default: take the host's leftmost label (e.g. hkust-gz, quantum-info). |
github-remote | (optional) | <org>/<repo> for the README clone link, e.g. CodingThrust/<topic>.harness. Empty leaves a <org>/<repo> placeholder. |
topic-blurb | (optional) | one paragraph for "Repository purpose". Empty leaves a TODO marker; user can edit CLAUDE.md afterwards. |
git-init | yes / no | run git init + a single seed commit. Default yes. |
Workflow
digraph init_harness {
"Collect inputs" [shape=doublecircle];
"Run scaffold.py" [shape=box];
"Verify (Done checklist)" [shape=box];
"github-remote provided?" [shape=diamond];
"User wants gh repo create now?" [shape=diamond];
"gh repo create + push" [shape=box];
"cd into target & invoke /onboard" [shape=box];
"Hand off to user" [shape=doublecircle];
"Collect inputs" -> "Run scaffold.py" -> "Verify (Done checklist)";
"Verify (Done checklist)" -> "github-remote provided?";
"github-remote provided?" -> "User wants gh repo create now?" [label="yes"];
"github-remote provided?" -> "cd into target & invoke /onboard" [label="no"];
"User wants gh repo create now?" -> "gh repo create + push" [label="yes"];
"User wants gh repo create now?" -> "cd into target & invoke /onboard" [label="no"];
"gh repo create + push" -> "cd into target & invoke /onboard";
"cd into target & invoke /onboard" -> "Hand off to user";
}
Phase 1 — Scaffold
Run the bundled helper. The SKILL_DIR must point to wherever this skill is installed. Resolve this by finding scaffold.py via the skill's own directory (the directory containing this SKILL.md).
SKILL_DIR="<path-to-this-skill's-directory>"
python3 "$SKILL_DIR/helpers/scaffold.py" \
--topic "<topic>" \
--target-dir "<target-dir>" \
--zulip-stream "project-<topic>" \
--zulip-site "<zulip-site-url>" \
--workspace "<workspace-slug>" \
--github-remote "CodingThrust/<topic>.harness" \
--topic-blurb "<one paragraph, or empty>" \
--git-init
The helper:
- Validates
--topic is lowercase + hyphenated.
- Refuses to scaffold into a non-empty target unless
--force is passed (don't pass --force without explicit user permission — the destination might be in-progress work).
- Verifies all required template files exist inside
templates/ before writing anything.
- Renders
Makefile, CLAUDE.md, README.md, .knowledge/INDEX.md from *.tmpl with <<TOPIC>>, <<ZULIP_STREAM>>, <<ZULIP_SITE>>, <<WORKSPACE>>, <<GITHUB_REMOTE>>, <<TOPIC_BLURB>> substituted.
- Copies
AGENTS.md and .gitignore verbatim (no substitution needed — already generic).
- Recursively copies
.claude/skills/onboard/SKILL.md from templates/skills/onboard/. The thin project-level onboard skill goes through the same substitution pass so its frontmatter description mentions the topic.
- If
--git-init: git init, git add ., single commit scaffold <topic>.harness from init-harness skill.
- Prints the file tree it wrote and a
next steps block.
Phase 2 — (Optional) create the GitHub repo
If --github-remote was provided AND gh is on $PATH AND the user agrees, run from inside <target-dir>:
cd "<target-dir>"
gh repo create "<github-remote>" --private --source=. --push \
--description "Reference / discussion harness for <topic>."
Confirm with the user before running — gh repo create is observable to the org and pushes the seed commit. Don't bundle this into Phase 1 silently.
If the user wants to invite a collaborator afterwards:
gh repo edit "<github-remote>" --add-collaborator <github-handle>
Skip this whole phase if github-remote is empty.
Phase 3 — Onboard the user to the new harness
The new harness ships a project-level .claude/skills/onboard/SKILL.md. It is a project-local skill and resolves only when the agent client is launched from inside the new harness directory.
cd "<target-dir>"
Notes:
- If the user has already enabled
zlp-harness from a previous harness, Phase A is a no-op and Phase B chains in immediately — no restart needed.
- If
<zulip-stream> doesn't yet exist on Zulip, make zulip-topics returns nothing (or an error). The bridge cannot auto-create the stream — an admin must create it via the Zulip web UI first. Tell the user; don't try to work around it.
- The bundled project-level onboard is site-agnostic — its description field stays generic, no per-harness patching needed beyond the topic substitution that Phase 1 already does.
Phase 4 — Hand off
Print a tight summary so the user knows what they own next:
Harness scaffolded at <target-dir>.
Next steps for the user:
1. cd <target-dir>
2. Edit CLAUDE.md — fill in "Repository purpose" and any linked external repos
(group code, scratchpad issue trackers).
3. Add the first references via the `download-ref` skill.
4. (If you skipped Phase 2) push to GitHub manually and invite collaborators.
5. Tell collaborators to clone and run /onboard.
Common mistakes
| Mistake | Fix |
|---|
Picking a topic with uppercase / spaces (e.g. Attention Solids) | Use lowercase, hyphenated (attention-solids). The slug appears in repo names, stream names, file paths — none of those should need shell quoting. The helper refuses uppercase / whitespace and exits 2. |
Pointing --target-dir at a populated directory | The helper refuses unless --force is passed. Don't pass --force without explicit user OK — you might clobber in-progress work. Pick a fresh directory instead. |
Reading from .../qec/.claude/skills/... while running this skill | Don't. This skill is standalone: every template lives under this skill's templates/ directory. If you find yourself hand-copying from another repo, you've taken a wrong turn — re-run the helper. |
| Skipping the GitHub-remote question because it's "optional" | Ask anyway. Without it the README contains a <org>/<repo> placeholder that breaks the one-line onboarding paste in README.md. Easier to set it now than retrofit. |
Pointing ZULIP_STREAM at a stream that doesn't exist on Zulip yet | The bridge can't create streams. Have the user (or Zulip admin) make the stream on the web UI first; only then will make zulip-topics succeed. |
Mixing up --zulip-site and --workspace | --zulip-site is the full URL (https://...); --workspace is the slug used in the workspace directory path (hkust-gz, quantum-info). The helper derives the latter from the host if you don't pass it. |
Running Phase 3's /onboard without cd-ing into the new repo | The project-level onboard only exists inside the new harness; running it from elsewhere either picks up a different harness's onboard or fails to find one. Always switch directories before invoking. |
| Editing the templates without testing the next scaffold | templates/ is the source of truth for every future harness; a typo here propagates. After editing any *.tmpl, run the helper into a scratch directory to verify the rendered output is what you expected. |
Bundling __pycache__/ from the local machine into templates/ | The helper's rglob skips __pycache__ parts explicitly, but be aware. |
Done checklist
After the helper finishes, verify (the user might do this themselves; if they don't, you do):