Local Single-Host Development Without Docker
Local Single-Host Development Without Docker
This document covers the smallest local Talon stack that still works with the current Sightline UI.
This mode runs:
- gateway as a local process
- worker as a local process
- SQLite for control-plane storage
- Unix socket broker for same-host event delivery
This mode does not use:
docker compose- Postgres
- Pub/Sub emulator
- a separate browser edge proxy
It is intended for one machine running both gateway and worker.
What each component does
SQLite: durable control-plane statelocal_socket: same-host broker transport between gateway and workerscheduler backend: delayed/background job storage and delivery, separate from the broker
Important separation:
- switching to
local_socketdoes not remove scheduler storage TALON_SCHEDULER_DRIVER=local_sqlitewill still create scheduler tables in SQLite- if you do not want scheduler tables, do not enable
local_sqlite
UI gateway endpoint
Sightline connects directly to the gateway, which serves both native gRPC and gRPC-Web on one port.
Use:
- Sightline UI:
http://localhost:3000 - gateway:
http://127.0.0.1:50051
Prerequisites
- Rust toolchain
- repository checked out locally
1. Build the binaries
From the repository root:
cargo build --offline --bin talon-server --bin talon-worker --bin talon-cli
If you are not using offline mode locally:
cargo build --bin talon-server --bin talon-worker --bin talon-cli
2. Create a temporary runtime directory
ROOT="$(mktemp -d /tmp/talon-local-XXXXXX)"
mkdir -p "$ROOT/data" "$ROOT/manifests"
This directory will hold:
- the config file
- the SQLite database
- the Unix socket broker
- any temporary manifests
3. Write the local config
Create $ROOT/config.yaml:
providers:
openai:
type: openai
model: gpt-5.4-nano
apiKey:
source: env
key: OPENAI_API_KEY
default_provider: openai
workspace_dir: .
control_plane:
database:
driver: sqlite
data_dir: ./data
message_broker:
driver: local_socket
data_dir is resolved relative to the config file directory.
With the config above, the live runtime artifacts will be created under:
$ROOT/data/talon-control-plane.db$ROOT/data/talon-broker.sock
If you only want to test control-plane behavior and will not run prompts, you
can leave providers empty and set default_provider: "".
4. Start the gateway
From the repository root:
env \
TALON_CONFIG_PATH="$ROOT/config.yaml" \
TALON_JWT_PRIVATE_KEY_PEM="$(cat ./src/control/security/test_rsa_private_key.pem)" \
TALON_JWT_ISSUER=https://talon.localhost \
GRPC_ADDR=127.0.0.1:50051 \
RUST_LOG=info \
./target/debug/talon-server
Expected startup lines include:
Connecting to SqliteKvStore at sqlite://$ROOT/data/talon-control-plane.db...
Initializing LocalSocketMessagePublisher at $ROOT/data/talon-broker.sock...
gRPC Gateway listening on: 127.0.0.1:50051
5. Bootstrap a local API key
Once the gateway is listening, mint a short-lived root bootstrap JWT from the private PEM and use it immediately to create a local API key:
export TALON_API_KEY="$(./target/debug/talon-cli --gateway http://127.0.0.1:50051 --token "$(TALON_JWT_ISSUER=https://talon.localhost ./target/debug/talon-cli auth local-token --private-key-pem-file ./src/control/security/test_rsa_private_key.pem)" auth api-key create --name local-dev --grant readwrite | awk -F= '/^secret=/{print $2}')"
Use the exported TALON_API_KEY for later CLI calls instead of reusing the
bootstrap JWT.
6. Start the worker
In a second terminal:
env \
TALON_CONFIG_PATH="$ROOT/config.yaml" \
PORT=18081 \
PULL_MODE=1 \
RUST_LOG=info \
./target/debug/talon-worker
Expected startup lines include:
Connecting to SqliteKvStore at sqlite://$ROOT/data/talon-control-plane.db...
Initializing LocalSocketMessagePublisher at $ROOT/data/talon-broker.sock...
Starting worker background subscriptions transport="local_socket"
If you explicitly want durable local scheduler storage too, add:
TALON_SCHEDULER_DRIVER=local_sqlite
TALON_LOCAL_SCHEDULER_RUNNER=1
Only add those when you want the scheduler tables and runner behavior.
7. Verify listeners
lsof -iTCP:50051 -iTCP:18081 -sTCP:LISTEN
You should see:
- gateway gRPC and gRPC-Web on
50051 - worker on
18081
8. Connect the UI
In Sightline, connect to:
http://127.0.0.1:50051
Use the API key from the bootstrap step when the auth modal asks for credentials.
9. Apply resources
Create a namespace manifest:
cat > "$ROOT/manifests/pretzel.namespace.yaml" <<'EOF'
apiVersion: talon.impalasys.com/v1
kind: Namespace
metadata:
name: pretzel
EOF
Create an agent manifest:
cat > "$ROOT/manifests/dj.agent.yaml" <<'EOF'
apiVersion: talon.impalasys.com/v1
kind: Agent
metadata:
name: dj
namespace: pretzel
spec:
systemPrompt: |
You are a concise local-development assistant.
modelPolicy:
profiles:
- name: default
model:
provider: openai
name: gpt-5.4-nano
temperature: 0.0
EOF
Apply the namespace:
./target/debug/talon-cli \
--gateway http://127.0.0.1:50051 \
--api-key "$TALON_API_KEY" \
apply --file "$ROOT/manifests/pretzel.namespace.yaml"
Apply the agent:
./target/debug/talon-cli \
--gateway http://127.0.0.1:50051 \
--api-key "$TALON_API_KEY" \
apply --file "$ROOT/manifests/dj.agent.yaml"
Verify through the edge:
./target/debug/talon-cli \
--gateway http://127.0.0.1:50051 \
--api-key "$TALON_API_KEY" \
get agents --namespace pretzel
Runtime artifacts
After startup, the runtime directory should contain:
$ROOT/data/talon-control-plane.db$ROOT/data/talon-broker.sock
Depending on SQLite activity, you may also see:
$ROOT/data/talon-control-plane.db-wal$ROOT/data/talon-control-plane.db-shm
If local_sqlite scheduler is enabled, you should also expect scheduler tables inside the same SQLite database.
Cleanup
Stop the worker and gateway processes, then remove the temp directory:
rm -rf "$ROOT"