Recipes
Copy-pasteable Runfile snippets for common workflows. Adjust names and paths to fit your project.
Docker workflows
# @desc Build the Docker image
docker:build() {
docker build -t myapp:latest .
}
# @desc Start services
docker:up() {
docker compose up -d
}
# @desc Tail logs for one or more services (defaults to app)
# @arg services Service names (optional)
docker:logs(...services) {
if [ $# -eq 0 ]; then
set -- app
fi
docker compose logs -f "$@"
}
Run with run docker build, run docker up, or run docker logs api web.
CI pipeline
# @desc Lint the project
lint() cargo clippy -- -D warnings
# @desc Run tests
test() cargo test
# @desc Build release binary
build() cargo build --release
# @desc Full CI
ci() {
echo "Running CI..."
lint || exit 1
test || exit 1
build
}
Polyglot data helpers
# @desc Analyze a JSON file
# @arg file Path to the JSON file
analyze(file: str) {
#!/usr/bin/env python3
import sys, json
data = json.load(open(sys.argv[1]))
print(f"Total records: {len(data)}")
}
# @desc Convert CSV to JSON
# @arg input Input CSV file
# @arg output Output JSON file
csv_to_json(input: str, output: str) {
#!/usr/bin/env python3
import sys, csv, json
rows = list(csv.DictReader(open(sys.argv[1])))
json.dump(rows, open(sys.argv[2], 'w'), indent=2)
print(f"Converted {len(rows)} rows -> {sys.argv[2]}")
}
Platform-specific commands
# @desc Clean build artifacts
# @os windows
clean() {
del /Q /S target\*
}
# @desc Clean build artifacts
# @os unix
clean() {
rm -rf target/
}
# @desc Open the project (portable)
open() {
case "$(uname -s)" in
Darwin) open . ;;
Linux) xdg-open . ;;
MINGW*|MSYS*|CYGWIN*) start . ;;
*) echo "Unsupported OS" >&2; return 1 ;;
esac
}
Deploy with dependencies
build() cargo build --release
# @desc Build and deploy
deploy(env: str, version = "latest") {
build || exit 1
echo "Deploying $version to $env"
./scripts/deploy.sh $env $version
}
Ad-hoc memory (SQLite recipe)
If you want memory-like behavior, you can do it with plain Runfile functions and an sqlite3 database. The top-level @instructions lines in this example are appended to MCP initialize.instructions, so the agent gets usage guidance
at session start.
# @instructions Use this SQLite recipe for facts discovered during a session that need to survive context compaction or carry across sessions (for example: resolved environment details, confirmed decisions).
# @instructions Prefer the host's own auto-memory (for example: MEMORY.md) for user preferences and workflow instructions that should be read at conversation start.
# @desc Create ad-hoc memory tables (idempotent)
memory:init(db = ".run-memory.db") {
sqlite3 "$db" "CREATE TABLE IF NOT EXISTS memories (id TEXT PRIMARY KEY, scope TEXT NOT NULL DEFAULT 'session', content TEXT NOT NULL, updated TEXT NOT NULL)"
sqlite3 "$db" "CREATE TABLE IF NOT EXISTS tags (memory_id TEXT NOT NULL, tag TEXT NOT NULL, PRIMARY KEY (memory_id, tag))"
sqlite3 "$db" "CREATE INDEX IF NOT EXISTS idx_memories_scope ON memories(scope)"
sqlite3 "$db" "CREATE INDEX IF NOT EXISTS idx_tags_tag ON tags(tag)"
}
# @desc Store or update a memory note
# @arg content Note to remember
# @arg scope session|project|global (default: session)
# @arg tags Comma-separated tags (optional)
# @arg id Optional existing ID to upsert
memory:store(content: str, scope = "session", tags = "", id = "", db = ".run-memory.db") {
memory:init "$db"
entry_id="${id:-m-$(date +%s)-$RANDOM}"
esc_content=$(printf "%s" "$content" | sed "s/'/''/g")
esc_scope=$(printf "%s" "$scope" | sed "s/'/''/g")
sqlite3 "$db" "INSERT INTO memories (id, scope, content, updated) VALUES ('$entry_id', '$esc_scope', '$esc_content', datetime('now'))
ON CONFLICT(id) DO UPDATE SET scope = excluded.scope, content = excluded.content, updated = datetime('now');"
sqlite3 "$db" "DELETE FROM tags WHERE memory_id = '$entry_id';"
IFS=',' read -ra parts <<< "$tags"
for tag in "${parts[@]}"; do
clean_tag=$(printf "%s" "$tag" | xargs)
[ -z "$clean_tag" ] && continue
esc_tag=$(printf "%s" "$clean_tag" | sed "s/'/''/g")
sqlite3 "$db" "INSERT OR IGNORE INTO tags (memory_id, tag) VALUES ('$entry_id', '$esc_tag');"
done
echo "$entry_id"
}
# @desc Recall notes by substring/scope/id
memory:recall(query = "", scope = "", limit = 20, id = "", db = ".run-memory.db") {
memory:init "$db"
where="1=1"
if [ -n "$query" ]; then
esc_query=$(printf "%s" "$query" | sed "s/'/''/g")
where="$where AND content LIKE '%$esc_query%'"
fi
if [ -n "$scope" ]; then
esc_scope=$(printf "%s" "$scope" | sed "s/'/''/g")
where="$where AND scope = '$esc_scope'"
fi
if [ -n "$id" ]; then
esc_id=$(printf "%s" "$id" | sed "s/'/''/g")
where="$where AND id = '$esc_id'"
fi
match_count=$(sqlite3 "$db" "SELECT COUNT(*) FROM memories WHERE $where;")
if [ "$match_count" = "0" ]; then
echo "No memories found for the provided filters." >&2
return 1
fi
sqlite3 -header -column "$db" "SELECT id, scope, content, updated
FROM memories
WHERE $where
ORDER BY updated DESC
LIMIT $limit;"
echo "Found $match_count matching memory note(s)." >&2
}
# @desc Forget a note by id
memory:forget(id: str, db = ".run-memory.db") {
memory:init "$db"
esc_id=$(printf "%s" "$id" | sed "s/'/''/g")
tags_deleted=$(sqlite3 "$db" "DELETE FROM tags WHERE memory_id = '$esc_id'; SELECT changes();")
memories_deleted=$(sqlite3 "$db" "DELETE FROM memories WHERE id = '$esc_id'; SELECT changes();")
if [ "$memories_deleted" = "0" ]; then
echo "No memory found for id '$esc_id'." >&2
return 1
fi
echo "Deleted memory '$esc_id' (tags removed: $tags_deleted)." >&2
}
# @desc Run store/recall/forget in one verification flow
# @arg content Note to round-trip verify
# @arg scope session|project|global (default: session)
# @arg tags Comma-separated tags (optional)
# @arg id Optional existing ID to upsert
memory:roundtrip(content: str, scope = "session", tags = "", id = "", db = ".run-memory.db") {
memory:init "$db"
stored_id=$(memory:store "$content" "$scope" "$tags" "$id" "$db")
esc_stored_id=$(printf "%s" "$stored_id" | sed "s/'/''/g")
esc_scope=$(printf "%s" "$scope" | sed "s/'/''/g")
esc_content=$(printf "%s" "$content" | sed "s/'/''/g")
recalled_count=$(sqlite3 "$db" "SELECT COUNT(*) FROM memories WHERE id = '$esc_stored_id' AND scope = '$esc_scope' AND content = '$esc_content';")
if [ "$recalled_count" = "0" ]; then
echo "Round-trip recall verification failed for '$stored_id'." >&2
return 1
fi
memory:forget "$stored_id" "$db"
echo "$stored_id"
echo "Round-trip verification succeeded for '$stored_id'." >&2
}
For more patterns, combine these with the guidance in Polyglot commands and Command composition.