Automatic agent registration
Availability: 0.12.0 contract. Versions through 0.11.0 do not expose this
directory. Check /health and the installation's published OpenAPI before using
GET /api/v1/agents.
Your application assigns each agent its ID. On the first successful authorized resource request carrying that ID, QilbeeDB durably records the association between the authenticated company and the unchanged external ID. There is no separate enrollment request and no QilbeeDB-generated business identifier.
Use a company integration policy to allow new IDs without adding an exact grant for each agent. Existing exact-grant credentials also participate when their requested scope is authorized. Registration does not grant access: company, capability, project, agent, mission, visibility, and private subject checks still run on every resource request.
Make the first request#
Issue an integration credential with memory_write and a policy permitting your
project, agent, mission, and visibility. Then send the usual memory command:
{
"contract_version": 1,
"idempotency_key": "consumer-run-928-first-observation",
"scope": {
"project_id": "support",
"agent_id": "consumer-agent-928",
"mission_id": null,
"visibility": "private"
},
"operation": {
"type": "create",
"record": {
"episode_type": "Observation",
"event_time_millis": 1700000000000,
"content": {"primary": "The agent observed a recoverable tool failure."},
"tags": ["tool-failure"],
"metadata": {"source": "consumer-run-928"}
}
}
}
Send this body to POST /api/v1/memory/commands with the integration bearer
credential. HTTP 200 retains the existing memory receipt contract. The new memory,
its receipt, retrieval metadata, change event, and first agent association commit
in the same synchronous WAL-backed memory batch. Validation or batch-preparation failure creates neither
the memory nor its agent association. A commit error or lost response requires
idempotent reconciliation, as described below.
The company is derived from authentication. agent_id is an opaque,
case-sensitive identifier of 1–256 UTF-8 bytes, with no control characters and at
least one non-whitespace character. QilbeeDB does not trim, normalize, or replace
it. Your application must use the same ID for the same company agent across
projects. An identical string in another company identifies a different agent.
An authorized resource read can also register an agent, including an empty successful memory query. Authentication failure, scope denial, malformed input, missing requested resources, and other failed operations do not register an agent merely because an ID appeared in the request. Health checks, login, credential inspection, and administrative directory reads do not enroll agents.
Private memory remains bound to the authenticating credential's subject. The agent ID is not a private owner selector, and first registration does not transfer ownership. The registered subject records who made the first successful observed request; it is not an exclusive right to use the ID. Other credentials in the same company may use that ID when their own authority allows it.
Inspect registered agents#
Use a company administrator credential or administrator login session with
credential_admin:
curl --get "$QILBEEDB_URL/api/v1/agents" \
--header "Authorization: Bearer $QILBEEDB_COMPANY_ADMIN_TOKEN" \
--data-urlencode 'contract_version=1' \
--data-urlencode 'limit=25'
The directory derives the company from the authenticated administrator. It does not accept a caller-selected company or allow ordinary integration credentials to enumerate the company. The global administrator uses the existing explicit company administration flow to obtain authority in the selected company.
Example response, with synthetic identifiers:
{
"contract_version": 1,
"company_id": "example-company",
"page": {
"agents": [
{
"agent_id": "consumer-agent-928",
"registered_at_millis": 1700000000123,
"registered_by": {
"credential_id": "3a13832a-a324-48a5-b6e3-bd453c95c201",
"subject_id": "company-agent-system"
},
"first_scope": {
"project_id": "support",
"agent_id": "consumer-agent-928",
"mission_id": null,
"visibility": "private"
},
"private_subject_id": "company-agent-system",
"trigger": {
"kind": "memory_command",
"record_id": "eb3c7e52-7944-4677-9e5d-5a7253f99252",
"revision": 1,
"action": "created"
}
}
],
"next_after_agent_id": null
}
}
| Field | Meaning |
|---|---|
agent_id |
The unchanged external ID, unique within this company |
registered_at_millis |
Server time when the association was committed |
registered_by |
Credential ID and subject making the first observed request |
first_scope |
The project, agent, mission, and visibility of that request |
private_subject_id |
The first request's private subject; null for shared scope |
trigger.kind = memory_command |
Includes the exact command record, revision, and action |
trigger.kind = successful_resource_request |
Successful scoped operation without a memory-command receipt |
next_after_agent_id |
Exclusive continuation ID; null when this traversal has no further observed row |
The association is immutable. Later requests, another project, a different permitted credential, or credential rotation do not replace the first record. Under concurrency, the first durable registration wins; arrival time at the network boundary does not define the winner. Existing registration never skips authorization or turns a denied operation into a success.
The directory exposes first-observation metadata, not active agent status, heartbeat, current project membership, business ownership, or a complete list of workspaces and memories. Use the application's own lifecycle system for those business decisions.
Continue a directory traversal#
limit defaults to 25 and accepts 1–100. When next_after_agent_id is non-null,
supply its exact value as the URL-encoded after_agent_id query parameter:
curl --get "$QILBEEDB_URL/api/v1/agents" \
--header "Authorization: Bearer $QILBEEDB_COMPANY_ADMIN_TOKEN" \
--data-urlencode 'contract_version=1' \
--data-urlencode 'limit=25' \
--data-urlencode "after_agent_id=$NEXT_AFTER_AGENT_ID"
Storage selects the company prefix before traversal and orders IDs by their UTF-8 bytes. The cursor is an external ID, not an offset or an opaque encoded snapshot. It is exclusive: a continuation does not repeat its boundary row. Pages are live. Concurrent registrations sorting before the cursor require a new traversal; registrations after it may appear in a continuation. No total count or snapshot completeness is claimed. Each request visits at most the requested page, a boundary row if present, and one continuation lookahead within the company.
Failures and retry behavior#
| Status | Directory behavior |
|---|---|
| 200 | Returns the company page, including an empty page |
| 400 | Invalid contract version, limit, cursor ID, or unknown query field |
| 401 | Missing, expired, revoked, or otherwise invalid authentication |
| 403 | Authenticated caller lacks company administration |
| 500 | Storage failure or inconsistent stored registration; no partial page is returned |
Response caching is disabled with Cache-Control: no-store. Internal storage
namespaces and credential secrets are never included in directory responses.
For memory commands, retry the identical command with the same idempotency key when the response is lost. An acknowledged command from before this feature can create its first post-upgrade association on a valid replay, without creating a new memory or changing its original receipt. A conflicting replay does not register the agent. This registration time denotes the post-upgrade observation, not the time of the original command.
Other scoped operations register after their operation succeeds and before the HTTP handler returns. They may use a different store or an earlier independent write. If registration then fails, the API returns an error even though that operation may already have committed. Reconcile using that operation's existing receipt, revision, or read contract; do not assume an error means no side effect. This feature does not add a transaction across identity, learning, and memory stores. Concurrent revocation retains the existing behavior: a request already authorized may finish. A lost HTTP response is not proof of rollback.
Upgrade, retention, and validation#
Collection begins when this feature runs. It does not scan old memories or infer
historical agent IDs from credential names. Historical agents appear after their
next successful authorized request. Existing memory and authorization namespaces
remain unchanged. The trusted Rust storage API only registers when its caller
supplies an AgentObservation; the server derives that observation from verified
authorization. Direct library callers remain responsible for authentication and
for binding company, ID, subject, and namespace correctly.
Deleting memories, expiring credentials, changing grants, and revoking access do not erase the immutable registration. It is retained first-observation metadata; this release has no registration removal, rename, or agent suspension endpoint. It does not reactivate credentials or authorize reads of deleted or private data.
Older binaries do not collect new observations. A mixed-version interval leaves a directory coverage gap until those agents make successful requests on a supporting version. Follow the stricter credential-policy downgrade requirements when policies or authority-change records have also been used.
Qualification covers real TCP responses against the served OpenAPI, empty reads, unchanged Unicode IDs, same-ID company isolation, capability and scope denial, revocation, invalid queries, bounded continuation, concurrent first writes, receipt replay, invalid stored metadata, and failed batches. A subprocess test kills the server after acknowledged memory and read registrations and verifies both associations and the original memory receipt after restart. These checks validate the registration contract; they do not establish retrieval relevance or improved agent reasoning.
The 0.12.0 company memory inventory is a separate directory derived from retained memory storage. Its startup migration includes pre-existing private workspaces without fabricating historical agent registration events.