一键导入
data-store
Govern provider-agnostic data reads and state transitions through declared data-source operations, not model-authored raw queries.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Govern provider-agnostic data reads and state transitions through declared data-source operations, not model-authored raw queries.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Governed runtime for agent skills: discover and install portable skills, run bounded skill graphs with explicit authority, and inspect signed receipts for what happened.
Audit a sealed runx receipt for governance, comparing the authority a run exercised against what it was granted, and flag over-reach, ungated mutation, unrecorded refusals, or exposed secret material.
Verify the receipt ids behind a normalized authority-usage summary, compare that evidence with granted scopes, and propose the narrowest grant the evidence supports.
Answer a cross-run audit question against the receipt ledger, returning matched receipts and a chain-verification result.
Read durable reflect projections, group repeated signals by skill, and emit validated handoffs to skill-lab improve when the evidence clears configured floors.
Review receipts and harness failures to propose bounded skill improvements.
| name | data-store |
| description | Govern provider-agnostic data reads and state transitions through declared data-source operations, not model-authored raw queries. |
| runx | {"category":"data"} |
Operate a data source through a governed adapter contract. This skill gives an agent enough context to read, append, or project state without learning provider secrets, inventing SQL, or depending on one storage backend.
The storage backend can be Postgres, SQLite, D1, Redis, DynamoDB, S3, a ledger, or a product API. The runx boundary is the same: a declared data source exposes typed operations; the graph supplies bounded params; the adapter executes the operation; the receipt records the resource, authority, idempotency, version, digest, and redaction evidence.
The operator chooses a data source at run time. The skill receives
data_source_ref and operation inputs; project or hosted configuration binds
that ref to the concrete adapter. A local development ref might be
local://runx-data-store/dev-board. A production ref might be
tenant://acme/board bound to data.postgres, data.d1, data.redis, or a
product-owned HTTP adapter.
Do not put provider logic in the domain skill. Messageboard, CRM, support, and business-ops skills should ask for durable facts to be read or written; the data source binding decides whether those facts live in local JSON, SQL, Redis, D1, object storage, or a product API. Switching providers is a binding change, not a rewrite of the skill.
The bundled OSS profile calls data.source. Unbound local://... refs default
to durable local SQLite under .runx/data/local-sources/, with one source-scoped
database file per logical ref, so stateful skills can be dogfooded without
standing up hosted infrastructure. Pass store_id only when a fixture
intentionally wants the deterministic data.local JSON store. The graph inputs
stay the same when a project later binds the source to Postgres, Redis, D1,
object storage, or a product API.
Adapter preference is operator configuration, not model choice. To choose Redis,
SQLite, or a hosted provider, bind the same data_source_ref through
RUNX_DATA_SOURCES or .runx/data-sources.json; do not add provider branches to
the domain skill.
data.local), durable local SQLite adapter
(data.sqlite), and Redis adapter (data.redis) behind the same operation
envelope.data_source_ref to name the project or
tenant source; let the project binding choose the adapter. Do not put raw
database URLs, provider credentials, or SQL in the skill input.needs_source: the data source, resource, query name, tenant key, or schema
summary is missing.needs_input: required operation params are incomplete, malformed, or not
specific enough to bind a declared data-source operation.needs_authority: the caller lacks the declared read/write scope or provider
grant.needs_version: a mutating operation lacks expected_version where the data
source requires optimistic concurrency.conflict: the current version differs from expected_version, or an
idempotency key is reused with different content.too_broad: the requested read lacks partition filters, exceeds limits, or
asks for raw export.redaction_required: the operation would return secrets, private PII, or
fields outside the declared projection.provider_unavailable: the adapter cannot reach the data source, times out,
or cannot prove whether a write committed.All runners return runx.data.operation_result.v1:
{
"schema": "runx.data.operation_result.v1",
"data_source_ref": "local://example",
"provider": "local-json-event-store",
"operation": "append_event",
"resource": "board_events",
"aggregate_id": "posting-123",
"status": "committed",
"before_version": 0,
"after_version": 1,
"idempotency_key": "posting-123:create",
"event_ref": "board_events:posting-123:1",
"result_digest": "sha256:...",
"projection_digest": "sha256:...",
"rows": [],
"events": [],
"redactions": [],
"stop_conditions": []
}
Provider adapters may add provider evidence under provider_evidence, but they
must not expose credentials or raw secret material.
For event streams, adapters derive a readable event_type in this order:
explicit event.type, explicit event.event_type, then
event.effect_family + "." + event.operation. Domain skills that emit the
generic runx.effect.transition.v1 packet should include effect_family and
operation on every event so readback projections say messageboard.accept,
business_ops.route, or another meaningful transition instead of data.event.
A messageboard skill decides that posting.claimed is allowed. It emits a
domain transition packet. The graph then calls data-store.append_event with
resource board_events, aggregate id posting-123, expected version 2, and
idempotency key posting-123:claim:agent-9. The data adapter appends the event
only if the stream is still at version 2. The receipt proves the decision,
the data operation, and the new version. A later loop turn calls
data-store.read_events or read_projection to resume from the explicit board
state.
data_source_ref (required): stable logical ref for the data source. The
project or hosted binding maps this ref to the concrete adapter and provider
profile.resource (required): declared resource, stream, table, keyspace, or
projection name.operation (required for tool-level use): append_event, read_events,
read_projection, or list_stream_heads.aggregate_id (required for event operations): stream or partition key.event (required for append_event): domain event or transition packet.idempotency_key (required for writes): stable retry key.expected_version (required when the source enforces concurrency): current
stream/resource version expected by the caller.limit (optional): maximum rows or events to return.after_version (optional for read_events): return an ascending page whose
event versions are strictly greater than this value. Omit it to retain the
existing latest-tail read. Compare the last returned event version with
after_version in the result envelope to know whether another page remains.event_types (optional for list_stream_heads): at most 20 exact latest
event types. No pattern or arbitrary field queries are accepted.cursor (optional for list_stream_heads): opaque cursor returned by the
previous page. Limits are capped at 100.store_id (local fixture adapter only): deterministic local store id that
opts into the bundled data.local proof adapter. Omit it for durable local
SQLite. Production adapters should ignore it.Durable local dogfood with the bundled default:
runx skill data-store append_event \
-i data_source_ref=local://runx-data-store/dev-board \
-i resource=board_events \
-i aggregate_id=posting-123 \
--input-json expected_version=0 \
-i idempotency_key=posting-123:create:v1 \
--input-json event='{"type":"posting.created","payload":{"title":"verify a receipt link"}}' \
--json
Fixture-only dogfood can still use store_id to select the JSON fixture store:
runx skill data-store append_event \
-i data_source_ref=local://runx-data-store/dev-board \
-i store_id=dev-board \
-i resource=board_events \
-i aggregate_id=posting-123 \
--input-json expected_version=0 \
-i idempotency_key=posting-123:create:v1 \
--input-json event='{"type":"posting.created","payload":{"title":"fixture proof"}}' \
--json
Production graph shape is the same at the skill boundary:
runx skill data-store append_event \
-i data_source_ref=tenant://acme/board \
-i resource=board_events \
-i aggregate_id=posting-123 \
--input-json expected_version=2 \
-i idempotency_key=posting-123:claim:agent-9 \
--input-json event='{"type":"posting.claimed","payload":{"actor":"agent-9"}}' \
--json
The second command only works once tenant://acme/board is bound to an
installed provider adapter. That binding is operator configuration and may name a
credential profile or hosted grant; it must not carry raw secrets.
Project-specific SQLite uses the same command shape after binding the source:
{
"data_sources": {
"tenant://acme/board": {
"adapter": "data.sqlite",
"database_path": ".runx/data/acme-board.sqlite",
"resources": {
"board_events": {
"kind": "event_stream",
"partition_key": "aggregate_id"
}
}
}
}
}
Pass that document through RUNX_DATA_SOURCES or .runx/data-sources.json.
Redis uses the same skill and graph inputs. Only the binding changes:
{
"data_sources": {
"tenant://acme/board": {
"adapter": "data.redis",
"endpoint": "redis://127.0.0.1:6379/0",
"key_prefix": "runx:{acme-board}",
"resources": {
"board_events": {
"kind": "event_stream",
"partition_key": "aggregate_id"
}
}
}
}
}
The Redis endpoint must not embed credentials. Use local unauthenticated Redis
for OSS dogfood, or put production secrets behind a runx credential profile or
hosted grant. For Redis Cluster, the binding's key_prefix must contain one
safe hash tag, such as {acme-board}, so the stream, idempotency, and head keys
touched by an append share one slot and update atomically. Stream-head pages use
stable keyset cursors rather than mutable offsets. Durable events and
dispositions must not receive TTLs; production Redis should enable persistence
and use a non-evicting policy.