v0.1.22 — Agent-card lifecycle bridges · Actionable fork errors · Skillify reads local manifests
Released 2026-05-13. macOS (Apple Silicon and Intel), Windows, and Linux all ship together. Install from codenow.pro/download .
This release came from dogfooding v0.1.21 by building a real agent (Sophia, an SDR agent) inside the IDE. Every bug found in that real-world use-case ships fixed.
The bugs that drove this release
Karl built Sophia — SDR Agent as a CodeNow project — entirely through Claude Code, no hand-coding — then opened the project tab to manage further development through the Studio surface. What he found:
- The Anatomy card auto-promoted with Sophia’s identity, skills rail, and chat input. Good.
- The chat input failed silently when run via the IDE — the only feedback was a 3-second toast saying “Run failed: Invalid API key” that vanished before he could read it. The actual cause was that Sophia’s
agent.tsdidn’t load.env, soprocess.env.ANTHROPIC_API_KEYwas undefined when the Claude Agent SDK started, but neither the toast nor the SDK error said that explicitly. - The Studio sub-tabs (Run / Test / Skillify / Trace / View log) were generic playgrounds with no idea Sophia existed. Clicking them showed empty surfaces because they don’t read from the manifest by default.
- Skillify in Business mode only knew about HTTP-imported agents, not locally-built filesystem-manifest agents. Sophia was invisible there.
- The Provider call log showed every Studio IPC call globally, but Sophia’s runs spawned via
npx tsx agent.tsbypass IPC entirely, so her actual usage was invisible.
Every gap above ships fixed in v0.1.22.
What’s new
1. Anatomy card grows five lifecycle bridges
Five new pill buttons land below the agent’s identity row, each pre-loading manifest data into the right Studio tab:
- Run in Studio — reads the manifest’s
prompts[]array, loads the first-system/-instructions/-policyprompt into the system field and any other prompt into the user-prompt field, checks the manifest’spreferredModelcheckbox, switches to the Run tab. - Test — switches to the Evals tab and highlights the first eval suite declared in the manifest.
- Skillify — switches to Business → Skillify, pre-selects the local manifest in the agent dropdown.
- Edit manifest — opens the manifest editor scoped to the agent’s slug.
- View log — opens the Provider call log scoped to this agent (see #4).
Without these, the Anatomy card was a render-only surface. Now it’s the orchestrator for the agent’s full lifecycle.
2. Actionable fork errors in the conversation panel
runs-fork (the IPC that powers the Anatomy chat) now classifies failures and returns a structured { reason, hint, docsHint, stderrTail } payload:
| Reason | Triggers when | Hint surfaced |
|---|---|---|
missing_api_key | stderr contains “anthropic_api_key”, “missing api key”, “authentication”, or “401" | "Missing ANTHROPIC_API_KEY (or it was rejected by Anthropic).” + fix: cp .env.example .env → add your Anthropic key → retry |
missing_dependency | stderr contains “cannot find module”, “module not found”, or “err_module_not_found" | "A required npm package is missing from this project.” + fix: cd <project> && npm install |
missing_runtime | stderr contains “command not found” or “enoent" | "tsx / Node was not on PATH when the agent ran.” |
timeout | process did not exit in 3 minutes | ”Agent run did not finish within 3 minutes…” |
exit_nonzero | process exited with a non-zero code without writing a run JSONL | ”Agent exited with code N before writing a run JSONL.” |
unknown | none of the above | Generic, with stderr tail attached |
The conversation panel renders an inline error card with the hint, a copy-paste fix command, a collapsible stderr tail, and a dismiss × button. The toast still fires for “something happened” feedback but the readable explanation lives in the card so a 3.2s toast doesn’t evaporate the only signal a stuck user gets.
3. Skillify reads local Studio manifests
populateAgentSelectors is now async and merges studioListAgents (your project’s .codenow/agent-studio/agents/*.json manifests) into the dropdown alongside execAgentsList (HTTP-imported registry agents).
Local entries use a local::<slug> value prefix; a new _skillifySelectorSplit helper routes them to:
- Storage:
<project>/.codenow/skills.json, tagged withagentSlugso multiple agents in one project don’t cross-contaminate each other’s skills. - Test invocation:
runsFork(same path the Anatomy card chat uses), not HTTP. The test result links back to the new Run’s JSONL in the Runs tab.
Imported HTTP agents keep their legacy execAgentsAddSkill / execAgentsInvoke paths unchanged.
4. Provider call log scoped by slug
openProviderTransparencyDrawer({ slug }) now optionally accepts an agent slug. When provided, the drawer fetches runsListForSlug(projectPath, slug) and renders a “Local agent runs” table above the Studio-calls table.
Each row links back to the Runs tab for full trace replay. The drawer header includes an honest disclosure: recorder JSONL files don’t capture per-call token/cost (those bypass CodeNow’s IPC entirely — agent.ts talks to Anthropic directly), so per-call cost is only shown for Studio-IPC calls.
5. Scaffolder ships a zero-dep .env / .env.local loader
The previous scaffolder template imported dotenv and loaded .env.local only. When Claude Code rewrote agent.ts for a real project (Sophia’s case), it dropped the dotenv import and the scaffolded loader was lost.
The replacement is an 8-line inline loader at the top of every scaffolded agent.ts:
import * as fs from "node:fs";
for (const envFile of [".env", ".env.local"]) {
try {
for (const line of fs.readFileSync(envFile, "utf-8").split("\n")) {
const m = line.match(/^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*?)\s*$/);
if (m && !process.env[m[1]]) process.env[m[1]] = m[2].replace(/^"(.*)"$/, "$1");
}
} catch (_) { /* file optional */ }
}Zero dependencies. Tries .env then .env.local. Survives an LLM rewriting agent.ts because there’s no import line to drop. Applies to both scaffoldClaudeAgentSdkTs and scaffoldCursorSdkTs.
Smoke gap closure
Two new smoke cases land alongside the polish bundle:
agent-card.action-handlers-defined— asserts all five card-action handlers (cardOpenInStudioRun/cardOpenInStudioEvals/cardOpenInSkillify/cardOpenInManifestEditor/cardOpenProviderLogForAgent) + the fork-error helpers (cardForkErrDismiss/cardForkErrCopy) are defined. Catches “feature shipped without wiring” — the exact failure mode that produced the v0.1.21 dogfooding gap.skillify.selector-splitter-routes-local-and-imported— proves_skillifySelectorSplitcorrectly routeslocal::<slug>to the local path, unprefixed values to the imported path, and empty values to the “no agent selected” path.
The existing popup-deadclick sweep added in v0.1.21 already covers the click-through end of the action buttons via the share-view-link-overlay registry pattern.
Runtime smoke: 120/120 green (was 118 in v0.1.21 + 2 new cases). Static smoke: 0 errors, 0 warnings.
Auto-updater behavior
Existing installs auto-update normally:
- v0.1.21 Apple Silicon, Intel, Windows, Linux users → v0.1.22 within ~4 hours of next launch, or Check for updates in the user menu.
- v0.1.17 — v0.1.20 users → v0.1.22 also picks up cleanly. Auto-update chain is reliable from v0.1.17 forward.
- v0.1.16 or older users → please do a fresh install. The pre-v0.1.17 updater had bugs that v0.1.17 fixed, and chaining through them is painful.
After update, your projects, keys, and settings in ~/.codenow survive the swap untouched.
CI note — Mac notarization retry
The initial CI run for this release tag failed at the Mac job’s final step: Apple’s notary service (appstoreconnect.apple.com) returned NSURLErrorDomain Code=-1001 "The request timed out." during the staple submission. Both DMGs had already been built, signed, and submitted successfully — the timeout was at the wait-for-Apple step. A simple re-run of the failed job (no code change) cleared cleanly on the second attempt.
This is an Apple-side flake that affects roughly 5–10% of notarized releases industry-wide. Tracking two possible mitigations for a future release:
- Parallelize the two Mac notarization submissions in
build/sign-and-notarize-dmg.js(currently serial — would shave ~10 min per build on a clean run). - Auto-retry on notary timeout in
.github/workflows/release.yml(would absorb the flake without a manual re-run).
Neither is urgent.
What’s queued
- The Sophia multi-tenant pattern shipped in her own repo (
github.com/karlmehta/sdr-agent) is the canonical reference for how to use the v0.1.22 lifecycle bridges. A future tutorial here will walk through that flow. - The v0.1.22 polish bundle deliberately did NOT add a “Run Sophia” / “Run <your agent>” first-class top-level button. The Anatomy chat input is the run path. If we hear that users want a more prominent CTA, a v0.1.23 polish bullet could add a primary “Run” button at the card’s top-right.
- Stripe billing + tier enforcement still queued. The v0.1.21 view-link endpoint already returns 402 for free-plan users; the v0.1.22 polish leans on the same gate where applicable. UI-side tier enforcement is the remaining work.