docs/agent-control.md
Rama main · réplica de lectura del repositorio original.
# Agent control through the API, CLI and MCP
The CLI and MCP use the versioned control API. API authorization remains authoritative.
The operation catalog comes from `api/openapi.json`. Dashboard and SDK types come from the same contract.
The contract classifies project operations, installation administration, dedicated execution tools and human consent flows.
Discovery lists the connection boundary, permissions, review requirements and prerequisites for each operation.
It also returns the operation summary and description from OpenAPI when those fields exist.
The [coverage inventory](agent-parity/coverage-matrix.md) records source coverage. It does not establish production availability.
The [research decisions](agent-parity/research-decisions.md) connect the work to public user reports and the Openship walkthrough.
## Discover and call operations
List operations without credentials:
```sh
hakopod api operations --family databases --limit 25
hakopod api operations --operation getManagedDatabase
```
Use the exact operation ID returned by discovery. Supply the returned cursor to read another page.
Inspect the operation parameters and body schema before a call.
Selected operations include the referenced schema definitions.
```sh
hakopod api call getManagedDatabase --project demo --environment development \
--path-json '{"id":"DATABASE_ID"}'
```
For a mutation, add `--allow-write`. Supply `--body-file FILE` when the operation requires JSON.
Use `--idempotency-key KEY` when the contract requires it.
The canonical endpoint still checks permissions, immutable revisions and resource ownership.
MCP provides `api_operations` and `api_call` with the same catalog and scope checks.
The dashboard proxy routes come from the same OpenAPI exposure metadata.
HTTP MCP dispatches operations through the canonical runtime API.
Installation administration uses a separate connection. Credentials need an additional explicit grant and connection option.
Streams, terminals and SQL use dedicated tools. Binary uploads and human consent retain their separate workflows.
Deployments use the existing reviewed plan flow. Deployment opt-in also enables cancellation, rollback and `restart_service` tools. No MCP tool sets a secret value; use `hakopod secret set` or the dashboard, so values never pass through an agent.
See [contract generation](agent-parity/contract-generation.md) for the generation process and drift checks.
## Separate permissions and opt-ins
| Action | API permission | CLI or stdio MCP option | HTTP MCP option |
| --- | --- | --- | --- |
| Generic mutations | Endpoint-specific permission | `--allow-write` | `allow_write=true` |
| Deploy, cancel or roll back | `deployments:write` | `--allow-deploy` | `allow_deploy=true` |
| Run a pod command | `pods:exec` | `--allow-exec` | `allow_exec=true` |
| Query managed SQL data | `databases:query` | `--allow-sql` for MCP | `allow_sql=true` |
| Change managed SQL data | `databases:query` and `databases:write-query` | `--allow-sql-write` | `allow_sql_write=true` with `allow_sql=true` |
| Add or change Kubernetes patches | `deployments:write` and `kubernetes:patch` | `--allow-deploy`, after `hakopod login --allow-kubernetes-patch` | `allow_deploy=true` |
| Open application terminals | `deployments:write` and `pods:exec` | `--allow-exec --allow-terminal` | `allow_exec=true` and `allow_terminal=true` |
| Use credentials | `agent:credentials` and the resource permission | `--allow-credentials` | `allow_credentials=true` |
| Administer the installation | `admin` and `agent:admin` | `--installation --allow-admin` | `installation=true` and `allow_admin=true` |
Each option enables only its action category. An option does not grant an API permission.
CLI and MCP resource inspection also require `deployments:read`. Include it when creating an execution key for those interfaces.
Machine keys require explicit execution permissions and a project/environment scope.
CLI credentials also require explicit execution permissions. An administrator wildcard does not enable machine or CLI execution.
Database query keys cannot have an application restriction.
SQL write grants require the SQL query grant.
Users must request and consent to execution permissions during device login.
`hakopod login --project P --environment E --allow-exec` requests `pods:exec`; `--allow-sql` and `--allow-sql-write` request the SQL grants. A session created without them cannot run `hakopod exec`: log in again with the flag.
Administrators can create API keys that never expire for CI and other long-lived integrations: choose **Never expires** in Settings, or run `hakopod key-create --name NAME --permissions ... --never-expires` from a browser-approved session. Only a self-hosted administrator in a browser session can create them. Revoke them when the integration no longer needs them.
Credential access can place secrets in an agent's context. Grant it only to trusted agents and integrations.
The [connection guide](agent-parity/connection-workflows.md) describes host-only access, stored node grants and bounded terminal polling.
## Pod commands
```sh
hakopod exec APPLICATION --project demo --environment development \
--service api --pod POD_NAME --container app --allow-exec \
--command-json '["/bin/sh","-c","printenv NODE_ENV"]'
```
Use the runtime API to obtain a current pod name. A command targets one owned service pod and container.
The API verifies the pod UID before execution. Commands use an argument array. A shell runs only when the command explicitly selects one.
The timeout is at most 20 seconds. Each output stream is limited to 64 KiB.
Commands accept at most 32 arguments. Each argument is limited to 4,096 bytes.
The process permits four concurrent pod commands. Excess output is discarded and marked as truncated.
Responses encode stdout and stderr as base64. A reported exit status means the transport observed process exit.
An `unknown` outcome does not establish process termination. Check the command effects before a retry.
Permission revocation closes the transport. Kubernetes does not guarantee that closing an exec connection terminates the process.
Audit records contain the command hash, target identity and outcome. They do not contain command or output bodies.
## Managed SQL queries
Read `getDatabaseQueryCapabilities` for the target engine before execution:
```sh
hakopod api call getDatabaseQueryCapabilities --project demo --environment development \
--path-json '{"id":"DATABASE_ID"}'
```
`supported` identifies enabled execution. `read_only_supported` identifies server-enforced read-only execution.
The response also specifies parameter syntax, execution modes and transaction guarantees. `transaction_scope` identifies guarantees for no transaction, one connection or one shard.
An unsupported engine or mode is rejected before connection. The current [verification record](agent-control-verification.md) lists qualified engines.
MyDuck uses its PostgreSQL endpoint with `$1` parameters and only `nontransactional` execution. It cannot enforce read-only queries: CLI and MCP callers must explicitly enable writes and supply the reviewed revision. Query capability discovery returns these same guarantees.
Oracle query support is limited to Oracle Database Free 23.26 in standalone mode with the platform's pinned image and required TLS. Enterprise and customer images remain unsupported. Oracle queries require explicit write permission and nontransactional execution. Oracle autonomous functions can commit outside the calling transaction, including from a `SELECT`. A parent rollback cannot prove that every write was undone. [Oracle's autonomous transaction documentation](https://docs.oracle.com/en/database/oracle/oracle-database/26/lnpls/autonomous-transactions.html) describes this behavior. Do not infer read-only safety from the statement's first keyword or the caller's transaction mode.
Vitess query execution retains the server's SINGLE transaction policy. Data changes must target one shard, including nontransactional requests. Reads may span shards. Schema changes can partially apply. `cross_shard_dml=false` reports that restriction. Standalone and sharded development acceptance passed against the same runtime source.
For PostgreSQL, save a query in a file:
```sql
SELECT $1::numeric, current_setting('transaction_read_only');
```
```sh
hakopod database query DATABASE_ID --project demo --environment development \
--sql-file query.sql --parameters-json '["9007199254740993"]'
```
The dedicated CLI query defaults to read-only. CLI and machine credentials require explicit SQL grants. An administrator wildcard does not grant SQL access. For a write, add `--allow-sql-write --revision REVISION` and use both SQL permissions.
Read the database revision before the write review. The API rejects a missing or changed write revision.
The dashboard database detail page links to the query page. The page reviews the target and statement before a write.
Queries use the managed application identity over verified TLS. The response does not expose database credentials.
PostgreSQL must accept the statement with `EXPLAIN`. Transaction control, `COPY` and multiple statements are unavailable.
Some data-definition statements support `EXPLAIN`, including `CREATE TABLE AS`. They require write access.
PostgreSQL read queries use a read-only transaction. Transactional writes commit only after a final authority check.
Use `--execution-mode nontransactional` only when the capability permits it and the intended statement requires it.
MySQL and Vitess retain a read-only transaction for read requests. Their nontransactional option applies to writes.
Some engines commit DDL implicitly. Nontransactional changes can persist after a failure, cancellation or result-limit error.
An engine without read-only enforcement requires explicit write access, including for a SELECT statement.
The dashboard never changes a read request into a write request automatically.
The process permits four concurrent queries. Each query has a 20-second deadline, at most 1,000 rows and at most 1 MiB of results.
The defaults are 100 rows and 256 KiB. Transactional writes attempt rollback when a result exceeds the bound.
Read results may be truncated. SQL null stays JSON null. Other cells use text to preserve numeric precision.
Query errors include an operation ID and outcome after execution begins.
An `unknown` outcome means the server cannot establish the final write result. Check the database before a retry.
Queries do not retry automatically. Audit records exclude SQL text, parameters, credentials and result rows.
The dashboard uses Monaco for SQL highlighting and keyword completion. PostgreSQL, MySQL and Vitess receive grammar hints from a local worker.
Grammar hints are advisory. They can flag valid bind placeholders or server extensions. Other dialects show an explicit linting limitation.
The editor sends no SQL to a third-party service. The control-plane API receives the statement only when the user runs it.
Editor input is limited to 64 KiB in UTF-8. Worker startup and parsing have separate deadlines, and a failure preserves the statement.
One worker retains at most one active request and the latest pending request. A later edit can start a new attempt after worker failure.
Press Escape to move from the editor to Parameters. If completion is open, the first Escape closes completion.
## Project and environment deletion
Self-hosted administrators can delete an empty project, including `demo` after first-time owner setup.
Project settings lists environments and provides deletion review. Project administrators can delete an empty environment through the dashboard.
Delete resources and reclaim retained data first. Remove scope grants and finish active operations before deletion.
The API checks for remaining resources while it locks the scope against concurrent creation.
Completed resource history stays available. Deletion revokes keys restricted to the removed scope.
Deleted IDs remain reserved. Create a project with a new name and ID to replace the default project.
Renaming an existing project changes its display name only.
CLI and MCP expose `deleteEmptyProject` and `deleteEmptyEnvironment` through the installation connection.
Both require installation administration permission and explicit write opt-in. Supply the exact project or environment ID in `confirm_name`.
These connection requirements do not grant authority to a scoped machine key.
Personal projects and their development environment remain linked to the account. Additional empty personal environments can be removed.
Cloud workspaces retain their separate runtime binding. Raw project deletion does not replace Cloud release or node-disconnection workflows.
## Verification and remaining work
See [the verification record](agent-control-verification.md) for checks performed on this change.
Native tests require the named `k3d-hakopod-dev` context and disposable fixtures.
UI fixtures contain artificial data and do not prove database connectivity.
The contract inventory is complete for this source snapshot. Native and production acceptance remain separate checks.
Cloud application terminal polling has separate native acceptance. Read the verification record for transport coverage and Cloud limitations.
Marketing claims must identify released capabilities and their tested limits.