nerdsane/temper/temper-developer

Claude Code and agent skill by nerdsane/temper

Trust tier 2
  • community
LLM review pending
Source check pending

Checking that the SKILL.md file is still in the repository.

Install

npx vskill@latest install nerdsane/temper/temper-developer

SKILL.md

Temper App Builder

You MUST use this skill when the user asks to build an app, create an application, or says "build me a X". Do NOT use other skills for app creation. Temper builds apps from verified specs, not from code. Interview FIRST, CLI LATER.

Step 0: Introduce the Experience

Before launching into the interview, briefly set expectations. The user is about to experience something different from normal software development. The core value to convey: they describe what they need in plain language, you turn it into a working app, and the app evolves through use — it is not static. Keep it to 2-3 sentences in your own words. Do not lecture. Then proceed to the interview.

Interview Protocol

When the user says "build me a X", have a quick, friendly conversation to understand what they want. Use plain language — no jargon. Do NOT run any CLI commands until the interview is complete. Keep it to 3 quick questions:

Step 1: What are you managing?

Ask: "What are the main things you'll be tracking or managing?"

Guide them toward nouns — projects, bugs, orders, people, tickets. Each one becomes an entity. Don't use the word "entity" with them. Say "thing" or use their word for it.

Example: "Sounds like you have Bugs and Developers — anything else?"

Step 2: What's the lifecycle?

For each thing, ask: "Walk me through the journey of a [Bug/Order/etc.] from start to finish. What stages does it go through?"

Keep it to 3-6 stages. Use their words. If they say "first it gets reported, then someone picks it up, then they fix it, then it's done" — that's Draft → Open → InProgress → Resolved.

Example: "Got it — so a Bug starts as Open, gets Triaged, someone Starts Work, then it's Resolved and finally Closed. Sound right?"

Step 3: What can go wrong or go sideways?

Ask: "Are there any special cases? Things that can be cancelled, restarted, or that shouldn't happen?"

This catches terminal states (Cancelled, Archived), backward transitions (Reopen), and rules (can't ship an empty order). Don't ask about "guards" or "invariants" — listen for "only if", "can't", "must", "not allowed" and translate those into guards/invariants yourself.

Example: "So a Closed bug can't be changed at all — it's final. And you can Cancel from anywhere except Closed. Got it."

Then summarize and confirm

Before generating anything, summarize in a simple table:

"Here's what I'll build:
- Bug: Open → Triaged → InProgress → Resolved → Closed (can Cancel from anywhere except Closed)
- Developer: Invited → Active → OnLeave (can Return from leave)
Look good?"

Wait for confirmation. Then generate specs.

Technical mapping (internal — don't show this to the user)
  • Their "stages" = states in [automaton]
  • Their "what you can do" = [[action]] entries with from/to
  • "Can't" / "not allowed" = [[invariant]] with assert (e.g. assert = "status in ['Shipped'] => items > 0")
  • "Only if" / "must have" = guard on the action
  • "Final" / "done forever" = terminal = [...] in [automaton]
  • Counters and flags: infer from context (e.g., "must have items" → counter items, guard items > 0)
  • Every guard and assert is one expression (&&, ||, !, =>, comparisons, in, empty(), len(), Type[ref].status, single-quoted strings); see docs/predicates.md

Generate Specs

Verify the temper CLI is available:

bash
temper --help

If missing: cargo install --git https://github.com/nerdsane/temper temper-cli.

Run temper init <project-name> in the user's working directory (not the temper repo). Then generate specs directly in specs/ — flat layout, no subdirectories (the CLI does not recurse).

Document storage rule

If your app produces a document-sized artifact, do not store the full artifact inline in entity fields.

Use inline string fields for:

  • titles
  • descriptions
  • comments
  • bounded notes
  • short prompts or summaries

Use Files plus content_file_id or another *FileId field for:

  • markdown pages
  • reports
  • transcripts
  • fetched documents
  • compiled analyses
  • HTML or rendered output
  • large JSON artifacts
  • long LLM outputs that must be read back in full

Pattern:

  1. create or update a Files entity
  2. upload bytes through Files('{id}')/$value
  3. persist only the file id on the entity
  4. keep entity fields focused on metadata and lifecycle state

Temper's blob-backed overflow behavior is a survivability safety net. It is not the preferred app design for document storage.

Write IOA Specs

Use the Write tool to create specs/<entity>.ioa.toml for each entity. Use this template:

toml
[automaton]
name = "EntityName"
states = ["State1", "State2", "State3"]
initial = "State1"
terminal = ["State3"]
[[state]]
name = "counter_var"
type = "counter" # "counter" | "bool"
initial = "0"
[[action]]
name = "ActionName"
kind = "input" # "input" | "output" | "internal"
from = ["State1"]
to = "State2"
guard = "counter_var > 0"
effect = ["counter_var += 1"]
params = ["Param1"]
hint = "Description for agents."
[[action.triggers]] # fires after ActionName commits
name = "notify_service"
kind = "wasm"
module = "notify_service"
on_success = "NotifySucceeded"
on_failure = "NotifyFailed"
[[invariant]]
name = "InvariantName"
assert = "status in ['State2', 'State3'] => counter_var > 0"
[[liveness]]
name = "EventuallyDone"
from = ["State1"]
reaches = ["State3"]

`effect` is a list of statements in the guard grammar (counter_var += 1, ready = true, append(tags, params.tag), schedule('Expire', 3600), ...; see docs/predicates.md#effects). Nothing is implied by an action's name — an AddItem with no effect changes only status. `[[action.triggers]]` is the only way an action causes work elsewhere (kind = "entity" | "wasm" | "adapter" | "webhook" | "hook"). [[integration]] blocks and trigger/emit effects fail to load; temper migrate-predicates <files> converts them.

IMPORTANT: Integrations use WASM modules, NOT webhooks. If the app needs external API calls (payments, notifications, email, etc.), you MUST generate a WASM module. See "Generate WASM Integration Modules" below — do NOT skip that section.

Write CSDL

Use the Write tool to create specs/model.csdl.xml. The CSDL must exactly match the IOA specs. Follow the mapping rules in the Reference section below.

Checklist before writing CSDL:

  • [ ] Every state in [automaton].states appears in StateMachine.States Collection
  • [ ] [automaton].initial matches StateMachine.InitialState
  • [ ] Spec annotation points to the .ioa.toml filename
  • [ ] Every kind = "input" or kind = "internal" action has a matching <Action>
  • [ ] Every action's from matches ValidFromStates; every to matches TargetState (omit for self-loops)
  • [ ] Every action's params become <Parameter> elements (after bindingParameter)
  • [ ] kind = "output" actions do NOT appear in CSDL
  • [ ] All <Action> entries have IsBound="true" with correct bindingParameter type
  • [ ] EntityContainer has an <EntitySet> for each EntityType
Write Cedar Policies (if needed)

Place Cedar policies in specs/policies/. Example:

cedar
permit(principal is User, action == Action::"read", resource is Order)
when { resource.ownerId == principal.id };
Generate WASM Integration Modules (if app needs external APIs)

When the app needs external API calls (payments, email, notifications, etc.):

  1. Add integration actions to the spec — a kind = "wasm" trigger on the action, plus callback actions:

```toml [[action]] name = "ChargeCard" from = ["Pending"] to = "Charging"

[[action.triggers]] name = "stripe_charge" kind = "wasm" module = "stripe_charge" on_success = "ChargeSucceeded" on_failure = "ChargeFailed"

[[action]] name = "ChargeSucceeded" kind = "input" from = ["Charging"] to = "Paid"

[[action]] name = "ChargeFailed" kind = "input" from = ["Charging"] to = "PaymentFailed" ```

  1. Generate WASM module source — create a Rust cdylib project:

``bash mkdir -p wasm-modules/<module_name>/src ``

Create `wasm-modules/<module_name>/Cargo.toml`: ```toml [package] name = "<module_name>" version = "0.1.0" edition = "2021"

[lib] crate-type = ["cdylib"] ```

Create `wasm-modules/<module_name>/src/lib.rs`: ```rust extern "C" { fn host_get_context(buf_ptr: i32, buf_len: i32) -> i32; fn host_set_result(ptr: i32, len: i32); fn host_http_call( method_ptr: i32, method_len: i32, url_ptr: i32, url_len: i32, body_ptr: i32, body_len: i32, resp_ptr: i32, resp_len: i32, ) -> i32; fn host_log(level_ptr: i32, level_len: i32, msg_ptr: i32, msg_len: i32); }

#[unsafe(no_mangle)] pub extern "C" fn run(_ctx_ptr: i32, _ctx_len: i32) -> i32 { // 1. Read invocation context let mut ctx_buf = [0u8; 4096]; let ctx_len = unsafe { host_get_context(ctx_buf.as_mut_ptr() as i32, ctx_buf.len() as i32) }; let _ctx = &ctx_buf[..ctx_len as usize];

// 2. Make your API call via host_http_call let method = b"POST"; let url = b"https://api.example.com/action"; let body = b"{}"; let mut resp_buf = [0u8; 8192]; let _status = unsafe { host_http_call( method.as_ptr() as i32, method.len() as i32, url.as_ptr() as i32, url.len() as i32, body.as_ptr() as i32, body.len() as i32, resp_buf.as_mut_ptr() as i32, resp_buf.len() as i32, ) };

// 3. Return result — "action" should match on_success/on_failure from the trigger let result = br#"{"action":"CallbackName","params":{},"success":true}"#; unsafe { host_set_result(result.as_ptr() as i32, result.len() as i32) }; 0 // return 0 for success } ```

Host functions available to WASM modules:

FunctionSignaturePurpose
host_get_context(buf_ptr, buf_len) -> actual_lenRead invocation context JSON (tenant, entity, trigger action, state)
host_set_result(ptr, len)Return result JSON to the host
host_http_call(method_ptr, method_len, url_ptr, url_len, body_ptr, body_len, resp_ptr, resp_len) -> statusMake an HTTP request (GET/POST/etc.)
host_log(level_ptr, level_len, msg_ptr, msg_len)Emit structured log (levels: "info", "warn", "error")

> Note: host_get_secret exists in the ABI but secret management is not yet supported. Do not use it — it will return empty results.

Result JSON format — set via host_set_result: ``json {"action": "CallbackName", "params": {"key": "value"}, "success": true} ``

  • action: the callback action name (should match on_success or on_failure in the trigger)
  • params: arbitrary JSON passed as parameters to the callback action
  • success: true triggers on_success, false triggers on_failure

Implement the required export:

  • pub extern "C" fn run(ctx_ptr: i32, ctx_len: i32) -> i32 — entry point called by the engine
  • Return 0 for success, non-zero for engine-level error (distinct from success: false in result JSON)
  1. Compile to WASM:

``bash rustup target add wasm32-unknown-unknown # one-time cd wasm-modules/<module_name> cargo build --target wasm32-unknown-unknown --release ``

  1. Upload module before deploying the spec:

``bash curl -X POST <TEMPER_URL>/api/wasm/modules/<module_name> \ -H "X-Tenant-Id: default" \ -H "Content-Type: application/wasm" \ --data-binary @target/wasm32-unknown-unknown/release/<module_name>.wasm ``

  1. Deploy spec as usual — the trigger invokes the WASM module when its action commits.

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewNot runA model review is scheduled for the next rescan.

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
46
Repository forks
10
7-day trend score
19

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/nerdsane/temper/temper-developer/badge)](https://verified-skill.com/skills/nerdsane/temper/temper-developer)

Something wrong with this skill or its page? Tell us.