mirror of
https://github.com/awizemann/scarf.git
synced 2026-05-10 10:36:35 +00:00
feat(projects,cron): new project wizard + keychain env mirror + #75 fix
Three coordinated additions to the project surface: 1. New Project from Scratch wizard. Toolbar entry that scaffolds a Scarf-standard project skeleton (`<project>/.scarf/dashboard.json` placeholder + `AGENTS.md` marker block), registers it, opens an ACP chat session in the project's cwd, and auto-sends a kickoff prompt that activates the bundled `scarf-template-author` skill. The skill drives the substantive setup conversationally — widgets, optional config schema, optional cron, AGENTS.md content. 2. Keychain secrets mirror into ~/.hermes/.env. Cron jobs can now reference Keychain-backed config values via env vars named `SCARF_<UPPER_SLUG>_<UPPER_FIELDKEY>`. Hermes reloads .env per cron tick (cron/scheduler.py:897-903), so credential rotation is free. Source of truth stays in the Keychain — config.json keeps `keychain://` URIs unchanged. Mirror runs at install, post-install Configuration save, uninstall, "Remove from List", and on app launch (reconcileAll). Mode 0600 on `.env` enforced by LocalTransport's existing `.env` heuristic. 3. Configuration form layout recursion fix (issue #75). Per-stage frame sizes on `ConfigEditorSheet` triggered `_NSDetectedLayoutRecursion` for projects with manifest.json. Stabilized the outer frame at the editing stage's intrinsic size so transitions only swap content, never resize the container. New services: - `ProjectScaffolder` (Mac) — bare-shell project + AGENTS.md marker - `SkillBootstrapService` (Mac) — copies bundled skills into ~/.hermes/skills/ - `KeychainEnvMirror` (Mac) — splice/unmirror/reconcileAll over ~/.hermes/.env - `SecretsEnvBlock` (ScarfCore) — pure marker-block helpers Bundled skill `scarf-template-author` v1.1.0 ships in `Resources/BuiltinSkills.bundle/`; SkillBootstrapService copies it into `~/.hermes/skills/scarf-template-author/` on launch (idempotent + version-gated). The skill grew a "Using secrets in cron prompts" section documenting the env-var convention. Migration: launch reconciler auto-populates .env on first v2.8 launch. Users with cron prompts authored against the old (broken) pattern need to update them to use $SCARF_… references — see release notes. Tests: - SecretsEnvBlockTests: 24/24 (`swift test --filter SecretsEnvBlock`) - KeychainEnvMirrorTests: 11/11 (`xcodebuild ... -only-testing:scarfTests/KeychainEnvMirror`) The idempotent-mirror test caught a real bug: applyBlock's replace path consumed the trailing newline from blockRange but didn't restore it, breaking the no-op-when-unchanged contract that the launch reconciler relies on. Fixed. v2.8 RELEASE_NOTES.md committed but no release cut yet. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: scarf-template-author
|
||||
description: Scaffold a new Scarf project — dashboard, optional configuration schema, optional cron job, and AGENTS.md — from a short conversational interview with the user. Output is immediately usable locally and cleanly exportable as a .scarftemplate bundle.
|
||||
version: 1.0.0
|
||||
version: 1.1.0
|
||||
author: Alan Wizemann
|
||||
license: MIT
|
||||
platforms: [macos]
|
||||
@@ -319,11 +319,40 @@ Where `cron/jobs.json` is:
|
||||
]
|
||||
```
|
||||
|
||||
### Using secrets in cron prompts
|
||||
|
||||
`secret`-typed config fields land in the macOS Keychain at install time, with `keychain://` URIs in `<project>/.scarf/config.json` (never plaintext on disk). At install + on every config save, **Scarf mirrors the resolved values into `~/.hermes/.env`** under env var names like `SCARF_<UPPERCASE_SLUG>_<UPPERCASE_FIELDKEY>`. Hermes's cron scheduler reloads `~/.hermes/.env` fresh on every tick, so the values are reachable from any tool the agent invokes.
|
||||
|
||||
**The agent reads them via the terminal or code_exec tool — not from prompt-text substitution.** Hermes does not interpolate env vars into prompt bodies. Tool-invoked subprocesses (the only path through which env vars become visible) DO see them via shell-level expansion or `os.environ`. Cron prompts should reference secrets in tool invocations, not in inline text.
|
||||
|
||||
**Naming.** For a template with `slug = "site-status-checker"` and a secret field `api_token`, the env var is `SCARF_SITE_STATUS_CHECKER_API_TOKEN`. Both halves are upper-cased and any non-`[A-Z0-9_]` characters become `_`. Stable across releases — write your prompts using these names and they'll keep working when the user rotates the secret.
|
||||
|
||||
**Example cron prompt (with a secret):**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Daily news digest",
|
||||
"schedule": "0 9 * * *",
|
||||
"prompt": "Use the terminal tool to fetch the RSS feed: `curl -sS -H \"Authorization: Bearer $SCARF_LOCAL_NEWS_API_TOKEN\" \"$SCARF_LOCAL_NEWS_RSS_URL\" -o {{PROJECT_DIR}}/.scarf/feed.xml`. Then summarise the top 5 items into {{PROJECT_DIR}}/.scarf/digest.md."
|
||||
}
|
||||
```
|
||||
|
||||
The agent runs `curl` via the terminal tool; the shell expands the env vars from the cron process's environment (which Hermes populated by loading `~/.hermes/.env`). For Python via the code_exec tool, use `os.environ['SCARF_LOCAL_NEWS_API_TOKEN']`.
|
||||
|
||||
**What NOT to do:**
|
||||
|
||||
- ❌ *"Read `keychain://...` from config.json and call the API with it."* Hermes treats the URI as opaque text — the API call sends `Authorization: Bearer keychain://...` and gets a 401.
|
||||
- ❌ *"Use the API token from values.api_token in config.json."* Same issue — the value in config.json is the URI, not the secret.
|
||||
- ❌ Inlining a secret into the prompt body and asking the agent to use it. Secrets shouldn't appear in prompts; that's why we route them through env vars.
|
||||
|
||||
**What about `~/.hermes/.env` rotation?** The user rotates a secret in Scarf's Configuration sheet → Scarf re-resolves from the Keychain → re-mirrors to `~/.hermes/.env` → next cron tick (Hermes reloads `.env` per tick) sees the new value. No cron-job edit needed.
|
||||
|
||||
### Gotchas
|
||||
|
||||
- **Hermes does not set a CWD when firing cron jobs.** Relative paths in the prompt resolve against wherever the Hermes process happens to be running, not the project. Always use `{{PROJECT_DIR}}` in the prompt — the installer substitutes the absolute path at install time. This is THE most common template-author mistake.
|
||||
- **Cron jobs created by the installer start paused.** Their name is auto-prefixed with `[tmpl:<template-id>]`. The user enables them from Scarf's Cron sidebar when ready.
|
||||
- **Registering a cron job for a user's local (non-exported) project:** run `hermes cron create --name "<descriptive name>" "<schedule>" "<prompt>"` directly, substituting the absolute `<project>` path for `{{PROJECT_DIR}}` yourself. Then `hermes cron pause <id>` so it doesn't run until the user opts in.
|
||||
- **Hermes does not substitute env vars into prompt text.** `$VAR` references in the prompt body are passed through verbatim. Env vars only become visible when the agent invokes a tool (terminal, code_exec) that runs in a subprocess inheriting the cron process's environment — see the "Using secrets in cron prompts" section above.
|
||||
|
||||
### Schedule quick reference
|
||||
|
||||
|
||||
Reference in New Issue
Block a user