Getting started
You need Rust 1.89 or later. It runs on Linux and macOS; see platform evidence. Python, Node and model weights are not needed.
#Install
From a source checkout, until the first crates.io release:
cargo install --path .This installs one command, affordance. Everything below uses it; you do not write Rust to build
an app.
#Render an app
echo '{"name":"world"}' | affordance render views/demo/hello.tsx --state -It prints Hello, world! [greet] and its spans. The greeting span marks text; the greet span
marks a visible action and the handler it runs. --json prints ids and spans for another
program. With no --tokenizer, render uses its bundled default (GPT-2), enough for an app that
writes no model-specific chat format.
The app is views/demo/hello.tsx:
export default function Hello({name = "world"}) {
return <box>
<span label="greeting">{`Hello, ${name}!`}</span>
<aff name="greet" onGreet={({name}) => ({name})}>{" [greet]"}</aff>
</box>;
}This is Affordance's TypeScript/JSX subset, interpreted in Rust (not React or Node). A render evaluates the app against its state, then layout decides its exact token IDs and the actions that survive. An action's handler changes the state; the next render shows it. See the language.
#Your first agent
affordance init my-agent
cd my-agentinit writes these files:
app.tsx: the agent. It shows the model its task and the log of what it has seen and done, offers ashelltool and ananswertool, and loops until the model answers.affordance.yaml: where it runs. A model server (any OpenAI-compatible server on127.0.0.1:8080), a machine (home: this machine's shell) and the agent with its task..gitignore: the run's journals (.affordance/) and local settings (affordance.local.yaml).affordance.d.tsandtsconfig.json: types for your editor (whatharness,model(), the hooks and the elements are), so it completes and checks the app. They describe the platform; nothing runs them.
Start a model server. No key is needed for a local one:
llama-server -m your-model.gguf --port 8080 --jinja # llama.cpp
# or: ollama serve (then use --set model.url=http://127.0.0.1:11434/v1 --set model.model=<name>)
# or: vllm serve <model> --port 8080Then run the agent:
affordance runaffordance run finds affordance.yaml in the current directory (or a parent), runs the agent
and prints a report when it stops: "stopped": {"answer": "..."}. Each agent's journal and trace
are in .affordance/<agent>/. The journal records every input the agent received, so
affordance run --resume continues the run exactly; affordance run --fresh starts over.
#Change a setting
- For one run:
affordance run --set model.url=http://other:8080/v1 --set model.context=32768. A key is a dotted path; a value is YAML. - For this machine only: put it in
affordance.local.yamlbesideaffordance.yaml(it is not committed). It layers over the main file. - From the environment: write
${VAR}or${VAR:-default}in a value. - To see what the run will use:
affordance configprints the resolved deployment, secrets hidden.
A hosted API takes its key from an environment variable (read at each call, never written to the journal):
model:
kind: chat
url: https://api.example.com/v1
model: some-model
context: 128000
key_env: EXAMPLE_API_KEYSee model bindings for SGLang and vLLM token-id serving, Anthropic and OpenAI Responses, and running agents for the full deployment format.
#The library
An app imports the bundled TSX library with @affordance/ paths:
import { useLog } from "@affordance/lib/log.tsx";
import { ModelContext } from "@affordance/lib/model.tsx";@affordance/ names the library as an import map names a package: the copy bundled with the
affordance command, or a directory the deployment names with library: path/to/views. Your own
files import each other by relative path.
#Next
- Write apps: running agents, the language and layout,
and the apps in
views/demo/. - Add HTTP or MCP: Fetch and MCP.
- Embed the engine in a Rust program (not needed to build apps): the
harness guide and examples/embedding/hello.rs
(
cargo run --release --example hello -- TOKENIZER.json). - Contribute: contributing and development.
Source: docs/GETTING_STARTED.md, about 3 minutes to read.