nerdsane/temper/temper-developer
Claude Code and agent skill by nerdsane/temper
- community
Checking that the SKILL.md file is still in the repository.
Install
npx vskill@latest install nerdsane/temper/temper-developerSKILL.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" =
statesin[automaton] - Their "what you can do" =
[[action]]entries withfrom/to - "Can't" / "not allowed" =
[[invariant]]withassert(e.g.assert = "status in ['Shipped'] => items > 0") - "Only if" / "must have" =
guardon the action - "Final" / "done forever" =
terminal = [...]in[automaton] - Counters and flags: infer from context (e.g., "must have items" → counter
items, guarditems > 0) - Every
guardandassertis one expression (&&,||,!,=>, comparisons,in,empty(),len(),Type[ref].status, single-quoted strings); seedocs/predicates.md
Generate Specs
Verify the temper CLI is available:
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:
- create or update a
Filesentity - upload bytes through
Files('{id}')/$value - persist only the file id on the entity
- 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:
`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].statesappears inStateMachine.StatesCollection - [ ]
[automaton].initialmatchesStateMachine.InitialState - [ ]
Specannotation points to the.ioa.tomlfilename - [ ] Every
kind = "input"orkind = "internal"action has a matching<Action> - [ ] Every action's
frommatchesValidFromStates; everytomatchesTargetState(omit for self-loops) - [ ] Every action's
paramsbecome<Parameter>elements (afterbindingParameter) - [ ]
kind = "output"actions do NOT appear in CSDL - [ ] All
<Action>entries haveIsBound="true"with correctbindingParametertype - [ ] EntityContainer has an
<EntitySet>for each EntityType
Write Cedar Policies (if needed)
Place Cedar policies in specs/policies/. Example:
Generate WASM Integration Modules (if app needs external APIs)
When the app needs external API calls (payments, email, notifications, etc.):
- 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" ```
- Generate WASM module source — create a Rust
cdylibproject:
``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:
| Function | Signature | Purpose | |
|---|---|---|---|
host_get_context | (buf_ptr, buf_len) -> actual_len | Read 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) -> status | Make 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 matchon_successoron_failurein the trigger)params: arbitrary JSON passed as parameters to the callback actionsuccess:truetriggerson_success,falsetriggerson_failure
Implement the required export:
pub extern "C" fn run(ctx_ptr: i32, ctx_len: i32) -> i32— entry point called by the engine- Return
0for success, non-zero for engine-level error (distinct fromsuccess: falsein result JSON)
- Compile to WASM:
``bash rustup target add wasm32-unknown-unknown # one-time cd wasm-modules/<module_name> cargo build --target wasm32-unknown-unknown --release ``
- 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 ``
- 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
- SKILL.md in the repositoryCheckingskills/temper-developer/SKILL.md
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
[](https://verified-skill.com/skills/nerdsane/temper/temper-developer)