First Commit and Read
This guide walks you through running the Asset Core daemons locally, sending a simple commit, and reading back the resulting state. It is designed to confirm that your environment is wired correctly end-to-end before you model more complex domains.
Prerequisites
Make sure you can run local processes and read token files. You will open two terminals so you can observe both daemons and the read path independently.
- Docker + Docker Compose (recommended) or Rust toolchain for local builds
- HTTP client (
curl) plusjqfor token extraction - Terminal with two windows or tabs
Step 1 - Start the daemons (Docker Compose)
From the Asset Core repository root:
docker-compose up -d
This starts the write and read daemons on ports 8080 and 8081 using ./data for storage. The commit log and token files will be created under that directory.
Step 2 - Set namespace and tokens
In the first terminal:
export ASSETCORE_NAMESPACE_ID=5001
export ASSETCORE_ADMIN_TOKEN=$(jq -r .token data/auth/tokens/admin.json)
export ASSETCORE_WRITE_TOKEN=$(jq -r .token data/auth/tokens/writer.json)
export ASSETCORE_READ_TOKEN=$(jq -r .token data/auth/tokens/reader.json)
Tokens are stored under data/auth/tokens in the Docker workflow (or ./.assetcore/auth/tokens for local binaries). Keep these tokens private and treat them as production credentials.
Verify it’s running:
curl -H "Authorization: Bearer $ASSETCORE_ADMIN_TOKEN" \
http://127.0.0.1:8080/v1/write/health
Expected response:
{
"status": "healthy",
"version": "0.1.0",
"api_version": "0.1.0",
"build_git_sha": "abc123",
"uptime_secs": 3600
}
Step 3 - Verify read daemon health
In the second terminal:
curl -H "Authorization: Bearer $ASSETCORE_READ_TOKEN" \
-H "x-assetcore-namespace: $ASSETCORE_NAMESPACE_ID" \
http://127.0.0.1:8081/v1/read/health
The read daemon tails the same commit log as the write daemon, and health checks require a namespace header. This is a simple way to confirm that the read path can see the namespace you plan to use.
Expected response includes readiness and freshness metadata.
Step 4 - Send your first commit
Provision the namespace (once) and then create a container and add fungible balance in a single transaction. This mirrors a realistic “create + seed” pattern without requiring any custom schema.
curl -X POST http://127.0.0.1:8080/v1/write/namespaces/${ASSETCORE_NAMESPACE_ID}/lifecycle \
-H "Authorization: Bearer $ASSETCORE_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"target_state":"provisioned","reason":"quickstart bootstrap"}'
curl -X POST http://127.0.0.1:8080/v1/write/namespaces/${ASSETCORE_NAMESPACE_ID}/commit \
-H "Authorization: Bearer $ASSETCORE_WRITE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"operations": [
{
"op": "CreateContainer",
"args": {
"container_id": 1001,
"kind": { "type": "balance" },
"owner": null,
"policies": null
}
},
{
"op": "AddFungible",
"args": {
"class_id": 100,
"key": 1,
"quantity": 500,
"location": {
"container_id": 1001,
"kind": "balance"
}
}
}
],
"idempotency_key": "first-commit-2026-01-15"
}'
Expected response:
{
"namespace": 5001,
"commit_id": "00000000000000000000000000000001",
"outcome": "Committed",
"world_seq_start": 1,
"world_seq_end": 1,
"event_count": 2,
"start_time_ms": 1769800000000,
"commit_time_ms": 1769800000123,
"server_correlation_id": "wr-0000000000000001-0000000000000042",
"echo": {
"idempotency_key": "first-commit-2026-01-15"
},
"created_entities": {
"containers": [1001]
}
}
The world_seq_start confirms your commit was assigned sequence number 1. This number is the public, per-namespace sequence you should use for auditability and replay.
Step 5 - Read back the state
Query the container balances:
curl -H "Authorization: Bearer $ASSETCORE_READ_TOKEN" \
http://127.0.0.1:8081/v1/read/namespaces/${ASSETCORE_NAMESPACE_ID}/containers/1001/balances
Expected response:
{
"container_id": 1001,
"balances": [
{
"class_id": 100,
"key": 1,
"quantity": 500
}
],
"server_correlation_id": "rd-0000000000000001-0000000000000042",
"freshness": {
"namespace": 5001,
"world_seq": 1,
"commit_log_world_seq": 1,
"lag": 0,
"lag_ms": 0
}
}
The freshness metadata shows that the read daemon has processed all commits through sequence 1. In production, you can use freshness to detect lag and enforce minimum-read sequencing.
Troubleshooting
”Connection refused” on commit
The write daemon isn’t running or is on a different port. Check the terminal for errors and verify the --config path is correct.
Empty balances on read
The read daemon hasn’t caught up to the write daemon. Check that both daemons use the same commit log path. The freshness metadata shows the latest world sequence applied.
”ContainerNotFound” error
The container ID in your read query doesn’t match what you created. Container IDs are integers, not strings.
”InvalidQuantity” error
Quantity must be greater than zero. Check your AddFungible operation.
Next steps
- Using the Python SDK - Repeat this workflow with typed Python helpers
- Containers and Assets - Learn about different container kinds
- Transactions - Full transaction structure reference