Hermes doesn't set a working directory when firing cron jobs, so any
relative path in a template's cron prompt (`.scarf/config.json`,
`status-log.md`, etc.) resolves against whatever dir Hermes happens
to be in — NOT the installed project. Practical effect: site-status-
checker's cron job fires, agent runs with relative paths, finds
nothing to read, silently bails. User sees "Run now" complete with
zero output and nothing updated on disk.
Fix: the installer now substitutes template-author placeholders in
cron prompts at install time, before calling `hermes cron create`.
The registered cron job carries a fully-qualified, CWD-independent
prompt.
Supported tokens (deliberately few — each is part of the template
format contract from now on):
- `{{PROJECT_DIR}}` — absolute path of the installed project dir.
The one that was motivating this fix; required for any cron prompt
that reads or writes project files.
- `{{TEMPLATE_ID}}` — the `owner/name` from the manifest, for
templates that want to tag delivery payloads or log lines.
- `{{TEMPLATE_SLUG}}` — the sanitised slug used by the installer for
dir name + skills namespace, for templates that want to reference
their skills install path.
Implemented as a static `ProjectTemplateInstaller.substituteCronTokens`
so it's testable as a pure function. Unsupported placeholders pass
through verbatim — template authors notice in testing that their
token didn't get replaced and either use a supported one or file
a request.
Site Status Checker v1.1.0 updated to use the tokens:
- cron/jobs.json prompt now opens with "Run the site status check
for the Scarf project at {{PROJECT_DIR}}" and references
{{PROJECT_DIR}}/.scarf/config.json, {{PROJECT_DIR}}/status-log.md,
and {{PROJECT_DIR}}/.scarf/dashboard.json explicitly.
- AGENTS.md gains a note explaining that the cron-registered prompt
carries absolute paths (installer substitutes at install time),
while interactive-chat agents can keep using relative paths.
- bundle rebuilt, catalog regenerated.
templates/CONTRIBUTING.md documents the three supported tokens under
the cron/jobs.json bullet so future authors don't have to discover
this by hitting the same CWD bug.
Tests:
- ProjectTemplateExampleTemplateTests.siteStatusCheckerParsesAndPlans
extended to assert the bundled prompt contains {{PROJECT_DIR}}
UNRESOLVED. If someone accidentally bakes an absolute path into
the template (their install dir), every user of that template
would get the wrong path — this test catches that.
- Four new substitution tests in ProjectTemplateInstallerTests:
resolves PROJECT_DIR / resolves ID + SLUG / leaves unknown tokens
untouched / substitutes repeated occurrences. All go through the
static helper directly; no install round-trip needed.
57/57 Swift tests + 24/24 Python tests pass. Catalog check clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.9 KiB
Contributing a template to Scarf
Thanks for packaging something up for other Scarf users. This guide walks you through the full submission flow end-to-end.
Before you start
- You need Scarf 2.2 or later installed to build + test your template.
- Your template must ship a cross-agent
AGENTS.md— that's the Linux Foundation open standard (agents.md) every major coding agent reads. Templates without one are rejected; Scarf specifically supports agent-portable projects. - Templates are free and MIT-licensed implicitly by submission. Don't submit anything you don't have rights to.
What makes a good template
- Scoped. One purpose per template. A "does-everything" template is harder to maintain than three focused ones.
- Agent-first. The
AGENTS.mdtells any agent how to interact with your project. Spell out the project layout, what each file is for, and what the agent should do when the user asks common questions ("run the X job", "add a Y"). - Self-contained prompts. Cron jobs + skills should not assume state the template doesn't ship. If you need a
sites.txt, haveAGENTS.mdtell the agent to bootstrap it on first run (seeawizemann/site-status-checkerfor the pattern). - Paused by default. Every cron job ships disabled — Scarf pauses new jobs on install. Write prompts that work whether fired by cron or invoked directly in chat.
- No secrets. No API keys, no hostnames, no paths specific to your machine. The catalog's CI secret-scan will block obvious cases but this is on you.
- No config writes. Templates must not modify
~/.hermes/config.yaml,auth.json, or any credential path. The installer refuses v1 bundles that claim to. If you need integration with, say, a specific MCP server, document the prerequisite in your README instead of trying to install it.
Step-by-step submission
1. Fork + clone
gh repo fork awizemann/scarf --clone && cd scarf
2. Create your template directory
mkdir -p templates/<your-github-handle>/<your-template-name>/staging
cd templates/<your-github-handle>/<your-template-name>/staging
Directory names are lowercase, hyphenated, stable: people will type them.
3. Author the bundle
Minimum required files under staging/:
-
template.json— manifest. Schema:{ "schemaVersion": 1, "id": "<your-handle>/<your-template-name>", "name": "Your Template Name", "version": "1.0.0", "minScarfVersion": "2.2.0", "minHermesVersion": "0.9.0", "author": { "name": "Your Name", "url": "https://…" }, "description": "One-line pitch shown in the catalog.", "category": "monitoring", "tags": ["short", "list"], "contents": { "dashboard": true, "agentsMd": true, "cron": 0, "instructions": null, "skills": null, "memory": null } }The
contentsclaim must exactly match what's instaging/— the validator cross-checks and rejects mismatches. -
README.md— shown on the catalog detail page. Include: what the project does, what the user has to do after install, how to customize, how to uninstall. -
AGENTS.md— the cross-agent spec. Include: project layout, first-run bootstrap (if any), what each cron job expects to happen, and answers to common user prompts ("what's the status","add a X", etc.). -
dashboard.json— the Scarf dashboard that renders on the catalog detail page and after install. See awizemann/site-status-checker/staging/dashboard.json for the schema in action.
Optional:
instructions/CLAUDE.md,instructions/GEMINI.md,instructions/.cursorrules,instructions/.github/copilot-instructions.md— agent-specific shims beyondAGENTS.md.skills/<skill-name>/SKILL.md— shipped skills, installed into~/.hermes/skills/templates/<slug>/on the user's side.cron/jobs.json— an array of cron job specs. Each hasname,schedule(e.g.0 9 * * *orevery 2h),prompt, optionaldeliver,skills[],repeat. The prompt may use these install-time placeholders — the installer substitutes them before registering the cron job with Hermes:{{PROJECT_DIR}}— absolute path of the newly-installed project dir. Required for any cron prompt that reads or writes project files — Hermes doesn't set a CWD when firing cron jobs, so relative paths (.scarf/config.json) won't resolve. Write{{PROJECT_DIR}}/.scarf/config.jsoninstead.{{TEMPLATE_ID}}— theowner/nameid from your manifest.{{TEMPLATE_SLUG}}— the sanitised slug used for the project dir name + skills namespace.
memory/append.md— markdown appended to the user'sMEMORY.mdbetween template-specific markers. Use sparingly — most templates don't need this.
4. Build the bundle
From the staging/ directory:
cd ..
zip -qq -r <your-template-name>.scarftemplate staging/
mv <your-template-name>.scarftemplate . # end up alongside staging/
Or equivalently:
cd staging && zip -qq -r ../<your-template-name>.scarftemplate . && cd ..
5. Test locally in Scarf
- Open Scarf → Projects → Templates → Install from File… → select your
.scarftemplate. - Walk through the preview sheet. Make sure every file, cron job, and memory block shown is something you meant to ship.
- Install into a scratch parent dir. Verify the dashboard renders. Enable the cron job(s) if any and trigger them manually to confirm your
AGENTS.mddrives the right behavior. - Right-click the project → Uninstall Template… → verify nothing unexpected remains.
6. Validate
Before opening the PR, run the catalog validator locally:
python3 tools/build-catalog.py --check
This checks every template in the repo (including yours), verifies the manifest matches the bundle contents, refuses bundles >5 MB, and flags common secret patterns. If it fails, fix the reported issues before pushing.
7. Open the PR
git checkout -b add-<your-template-name>
git add templates/<your-handle>/<your-template-name>
git commit -m "feat(templates): add <your-template-name>"
git push origin add-<your-template-name>
gh pr create
Do not modify templates/catalog.json — the maintainer regenerates it after merge to keep PR diffs small.
The scarf repo ships a tailored submission checklist at .github/PULL_REQUEST_TEMPLATE/template-submission.md. To apply it to your PR, append ?template=template-submission.md to the compare URL when opening the PR in the browser, or copy the checkbox list into the body manually.
GitHub Actions runs the validator on your PR (see .github/workflows/validate-template-pr.yml). A green check means the bundle structure is sound; it doesn't mean the content is approved. Expect a maintainer pass for content quality (is the AGENTS.md clear, does the prompt do what you describe, is the scope reasonable).
8. Iterate + ship
Respond to review feedback. Common requests:
- Sharpen the
README.mdso install/uninstall steps are copy-pasteable. - Split ambitious cron prompts into smaller, clearly-scoped ones.
- Remove things the template doesn't need (an empty
skills/dir, an unuseddelivertarget, etc.).
Once merged, your template shows up at https://awizemann.github.io/scarf/templates/<your-handle>-<your-name>/ within a few minutes (the maintainer pushes the site regeneration by hand).
Updating an existing template
Bump version in template.json, rebuild the .scarftemplate, commit, PR. The Install button on the catalog always points at the latest main version — there's no per-version pinning in v1. Users who already installed get no automatic update; they'd have to uninstall + reinstall for v2.
Questions?
Open a GitHub Discussion — the tag templates is watched.