Operator Day-2 Operations¶
This page starts after register has returned an operator API key and the local staker-console profile exists. Command registration is in staker-console/src/index.ts:121.
status¶
What it does¶
status reads the current seat lifecycle state, lifecycle evidence, operation history, on-chain evidence, economics, and open exception signals for one local profile. The console command is registered at staker-console/src/index.ts:121, and the implementation resolves the local profile API base before calling the backend in staker-console/src/commands/status.ts:99.
When to use it¶
Run it after onboarding, before every claim, before exit or migrate, after a failed operation, and when the admin console reports a degraded watcher. The CLI prints the seat id, status, vault, risk state, claim gate state, exit-trigger status, reserve coverage, and open exceptions in staker-console/src/index.ts:141.
CLI invocation¶
export STAKER_CONSOLE_WORKSPACE=/var/lib/centurion-staker
staker-console-v2 status \
--seat-id <seat_id> \
--workspace "$STAKER_CONSOLE_WORKSPACE" \
--api-base https://seat-manager.example.org \
--json
--seat-id disambiguates multiple local profiles, --workspace points at the local profile store, --api-base overrides the sm_url saved in the profile, and --json prints the backend response. These flags are registered in staker-console/src/index.ts:121.
Required scope¶
The operator API key must carry status, one of the OperatorApiScope values declared in seat-manager/src/onboarding/store.ts:191. The default post-register key includes status, claim, and rotate_api_key in seat-manager/src/onboarding/store.ts:201.
Backend endpoint¶
GET /v1/seats/:seatId/status uses bearer authentication with the operator API key, requires the key to belong to the path seat, requires status scope, and rate-limits reads to 60 per minute in seat-manager/src/api/server.ts:1782. It has no idempotency key because it is a read.
State change¶
None. The route reads LifecycleEvidence, Operation, OperationTxIntent, on-chain evidence, and economics, then emits seat.status_read audit detail in seat-manager/src/api/server.ts:1802 and seat-manager/src/api/server.ts:1972.
Error modes¶
UNAUTHORIZED means the API key is absent, invalid, revoked, or expired; the store checks key expiry in seat-manager/src/onboarding/prismaStore.ts:390. FORBIDDEN means the key belongs to a different seat or lacks status scope in seat-manager/src/api/server.ts:1791. RATE_LIMITED comes from the status rate limiter in seat-manager/src/api/server.ts:1796. ONCHAIN_ECONOMICS_UNAVAILABLE can appear inside economics when adapters cannot read contracts; treat that as a backend/runtime issue, not an operator CLI issue.
claim¶
What it does¶
claim asks the backend to enqueue a reward claim operation for the seat. The console command is registered at staker-console/src/index.ts:198, and the command resolves the profile, reads current status/economics, then calls the API in staker-console/src/commands/claim.ts:252.
When to use it¶
Use it only after status shows claim policy open, running claims enabled, no open pending claim, and enough claimable rewards. The backend performs the final claim gate check and rejects claims that fail current economics or executor authorization in seat-manager/src/api/server.ts:2136.
CLI invocation¶
export STAKER_CONSOLE_WORKSPACE=/var/lib/centurion-staker
staker-console-v2 claim \
--seat-id <seat_id> \
--workspace "$STAKER_CONSOLE_WORKSPACE" \
--api-base https://seat-manager.example.org \
--max-amount-wei <optional_cap_wei> \
--confirm-claim CLAIM \
--json
--confirm-claim CLAIM is mandatory and enforced before the command calls the backend in staker-console/src/index.ts:210. --max-amount-wei is optional; it caps the requested amount in the claim payload and is registered in staker-console/src/index.ts:207.
Required scope¶
The key must carry claim, declared at seat-manager/src/onboarding/store.ts:191 and included in the default key in seat-manager/src/onboarding/store.ts:201. A rotated key that omits claim cannot submit this command.
Backend endpoint¶
POST /v1/claims uses bearer authentication, requires claim scope, requires an Idempotency-Key, and has a write limit of 40 per window in seat-manager/src/api/server.ts:2077. The console API client posts to /v1/claims and supplies a stable idempotency key when none is passed in staker-console/src/lib/api.ts:362.
State change¶
The route writes an audit event seat.claim_requested, enqueues an Operation with kind claim, stores a request hash, and saves the idempotent response in seat-manager/src/api/server.ts:2167, seat-manager/src/api/server.ts:2176, and seat-manager/src/api/server.ts:2210. The operation worker later writes OperationTxIntent rows and moves the operation through queued, processing, submitted, confirmed, and finalized in seat-manager/src/watchers/operationWorker.ts:156.
Error modes¶
UNAUTHORIZED means the key is invalid in seat-manager/src/api/server.ts:2084. FORBIDDEN means the payload seat does not match the key in seat-manager/src/api/server.ts:2098. BAD_REQUEST with Claim not allowed means the claim gate, signer, adapter, vault, or executor scope check failed in seat-manager/src/api/server.ts:2103 and seat-manager/src/api/server.ts:2143. OPERATION_ALREADY_PENDING comes from duplicate live work for the same seat and kind in seat-manager/src/onboarding/prismaStore.ts:1235. IDEMPOTENT_REPLAY_MISMATCH means the same idempotency key was reused with different payload in seat-manager/src/onboarding/prismaStore.ts:591.
exit¶
What it does¶
exit enqueues a voluntary validator exit operation through the backend executor path. The console command is registered at staker-console/src/index.ts:230, resolves the local profile and API base in staker-console/src/commands/exit.ts:44, and posts a reason field to the backend.
When to use it¶
Use it when Foundation Ops has enabled the operator key for voluntary_exit, the validator is deposited or later, the vault has exit trigger readiness, and status shows no existing exit operation still pending. Do not use it as a recovery shortcut for ordinary claim failures.
CLI invocation¶
export STAKER_CONSOLE_WORKSPACE=/var/lib/centurion-staker
staker-console-v2 exit \
--seat-id <seat_id> \
--workspace "$STAKER_CONSOLE_WORKSPACE" \
--api-base https://seat-manager.example.org \
--reason "operator-requested voluntary exit" \
--confirm-exit EXIT \
--json
The confirmation phrase is mandatory in staker-console/src/index.ts:239. The --reason flag is optional and is passed into the operation payload in seat-manager/src/api/server.ts:2032.
Required scope¶
The key must carry voluntary_exit, which is a valid OperatorApiScope but is not in DEFAULT_OPERATOR_API_SCOPES at seat-manager/src/onboarding/store.ts:191 and seat-manager/src/onboarding/store.ts:201. A default post-register key cannot run this command.
Backend endpoint¶
POST /v1/seats/:seatId/voluntary-exit uses bearer authentication, requires the key to match the path seat, requires voluntary_exit scope, requires an Idempotency-Key, and enforces write limit 20 in seat-manager/src/api/server.ts:1984. The console client posts to that path through submitVoluntaryExit in staker-console/src/lib/api.ts:379.
State change¶
The route emits seat.voluntary_exit_requested, enqueues an Operation with kind voluntary_exit, stores a deterministic request hash, and saves the idempotent 202 response in seat-manager/src/api/server.ts:2023, seat-manager/src/api/server.ts:2032, and seat-manager/src/api/server.ts:2065. On chain, the operation worker calls the controller exit request path; already-submitted exit status is terminal for the worker in seat-manager/src/watchers/operationWorker.ts:41.
Error modes¶
UNAUTHORIZED is an invalid key, FORBIDDEN is wrong seat or missing scope, and BAD_REQUEST covers disallowed lifecycle state or failed exit preflight in seat-manager/src/api/server.ts:1992, seat-manager/src/api/server.ts:2007, and seat-manager/src/api/server.ts:2008. OPERATION_ALREADY_PENDING means an outstanding exit operation already exists. IDEMPOTENT_REPLAY_MISMATCH means the idempotency key was reused for a different body.
migrate¶
What it does¶
migrate enqueues the phase-1 migration-triggered exit operation. The console command is registered at staker-console/src/index.ts:259, and its implementation resolves the local profile and calls the backend from staker-console/src/commands/migrate.ts:44.
When to use it¶
Use it only for the approved migration process. It shares the exit execution path, but it records the operation kind as migrate and action as migrate_trigger_exit, which lets the admin operations page distinguish it from an operator voluntary exit in seat-manager/src/api/server.ts:2296.
CLI invocation¶
export STAKER_CONSOLE_WORKSPACE=/var/lib/centurion-staker
staker-console-v2 migrate \
--seat-id <seat_id> \
--workspace "$STAKER_CONSOLE_WORKSPACE" \
--api-base https://seat-manager.example.org \
--reason "phase-1 migration" \
--confirm-migrate MIGRATE \
--json
The confirmation phrase is mandatory in staker-console/src/index.ts:271. The optional reason is saved in the operation payload at seat-manager/src/api/server.ts:2270.
Required scope¶
The key must carry migrate, declared in seat-manager/src/onboarding/store.ts:191. The default key omits it in seat-manager/src/onboarding/store.ts:201, so migration needs an explicitly scoped key.
Backend endpoint¶
POST /v1/seats/:seatId/migrate uses bearer authentication, requires migrate scope, requires an Idempotency-Key, and enforces write limit 20 in seat-manager/src/api/server.ts:2222. The console client posts through migrateSeat in staker-console/src/lib/api.ts:395.
State change¶
The route emits seat.migrate_trigger_exit_requested, enqueues an Operation with kind migrate, stores the request hash, and saves the idempotent response in seat-manager/src/api/server.ts:2261, seat-manager/src/api/server.ts:2270, and seat-manager/src/api/server.ts:2303. The on-chain effect is the same exit request path used by voluntary exit, but the operation kind stays distinct.
Error modes¶
UNAUTHORIZED and FORBIDDEN have the same meaning as exit. BAD_REQUEST covers disallowed lifecycle state, failed exit preflight, or missing contract adapters in seat-manager/src/api/server.ts:2245 and seat-manager/src/api/server.ts:2247. OPERATION_ALREADY_PENDING and IDEMPOTENT_REPLAY_MISMATCH have the same operator recovery as exit: check status, inspect operations, then retry with the same payload or use admin triage.
rotate-api-key¶
What it does¶
rotate-api-key asks Seat Manager to issue a new operator API key for the same seat, writes it into the local profile, and keeps the returned scopes. The command is registered at staker-console/src/index.ts:168, and the implementation stores the rotated profile in staker-console/src/commands/rotateApiKey.ts:28.
When to use it¶
Use it after suspected exposure, before a planned machine replacement, after staff handoff, or during periodic key hygiene. Run status immediately after rotation to prove the new profile works.
CLI invocation¶
export STAKER_CONSOLE_WORKSPACE=/var/lib/centurion-staker
staker-console-v2 rotate-api-key \
--seat-id <seat_id> \
--workspace "$STAKER_CONSOLE_WORKSPACE" \
--api-base https://seat-manager.example.org \
--confirm-rotate ROTATE \
--json
The confirmation phrase is mandatory in staker-console/src/index.ts:176. The command prints a preview of the new key and the updated profile path in staker-console/src/index.ts:192.
Required scope¶
The current key must carry rotate_api_key. That scope is declared in seat-manager/src/onboarding/store.ts:191 and is included in the default key in seat-manager/src/onboarding/store.ts:201. The backend refuses a rotate request that tries to grant scopes absent from the current key in seat-manager/src/api/server.ts:2353.
Backend endpoint¶
POST /v1/seats/:seatId/operator-api-key/rotate uses bearer authentication, requires the key to match the path seat, requires rotate_api_key, requires an Idempotency-Key, and enforces write limit 20 in seat-manager/src/api/server.ts:2315. The console client posts to the same path in staker-console/src/lib/api.ts:411.
State change¶
The store updates Seat.operator_api_key_expires_at, marks old active keys revoked after the rotation grace period, inserts a new OperatorApiKey, and returns the new plaintext key once in seat-manager/src/onboarding/prismaStore.ts:416. The route stores the idempotent response and emits seat.operator_api_key_rotated in seat-manager/src/api/server.ts:2389 and seat-manager/src/api/server.ts:2416.
Error modes¶
UNAUTHORIZED means the old key no longer authenticates. FORBIDDEN means wrong seat, missing rotate_api_key, or requested scopes not present on the current key in seat-manager/src/api/server.ts:2330 and seat-manager/src/api/server.ts:2344. SEAT_NOT_FOUND comes from the store when the seat id cannot be found in seat-manager/src/onboarding/prismaStore.ts:421. IDEMPOTENT_REPLAY_MISMATCH means the key was reused with a different rotate body.
verify-artifact¶
What it does¶
verify-artifact is a local release-artifact check. It computes SHA-256 for a file and can also call cosign verify-blob when a signature and public key are supplied. The command is registered at staker-console/src/index.ts:291, and the implementation requires at least one trust anchor in staker-console/src/commands/verifyArtifact.ts:80.
When to use it¶
Use it before installing a staker-console binary, moving a bundle onto a validator host, or comparing a downloaded artifact with a release checksum.
CLI invocation¶
staker-console-v2 verify-artifact \
--file ./staker-console-v2-linux-x64.tar.gz \
--sha256 <64_hex_checksum> \
--cosign-signature ./staker-console-v2-linux-x64.tar.gz.sig \
--cosign-public-key ./cosign.pub \
--json
--file is required, --sha256 is optional only when cosign inputs are present, and --cosign-binary defaults to cosign; the flags are registered in staker-console/src/index.ts:291.
Required scope¶
None. This is a local command. It does not use OperatorApiScope and does not read the operator API key.
Backend endpoint¶
None. This is a local command and produces no backend request.
State change¶
None. It reads the artifact file, computes SHA-256 in staker-console/src/commands/verifyArtifact.ts:94, optionally verifies cosign data in staker-console/src/commands/verifyArtifact.ts:111, and prints local results.
Error modes¶
Missing file access fails before hashing in staker-console/src/commands/verifyArtifact.ts:94. An invalid checksum format or mismatch fails the checksum path in staker-console/src/commands/verifyArtifact.ts:99. Supplying only one cosign input fails because signature and public key are required together in staker-console/src/commands/verifyArtifact.ts:111.
verify-token¶
What it does¶
verify-token verifies an enrollment JWT locally without running onboarding. The command is registered at staker-console/src/index.ts:321, and the implementation defaults to strict verification in staker-console/src/commands/verifyToken.ts:33.
When to use it¶
Use it before running onboard, when diagnosing an enrollment email, when checking issuer/audience mismatch, or when proving that a token points at the expected sm_url before any network request.
CLI invocation¶
staker-console-v2 verify-token \
--token "$CENTURION_ENROLLMENT_JWT" \
--issuer-public-key ./enrollment-issuer.pub.pem \
--issuer centurion-seat-manager \
--audience centurion-operators \
--mode strict \
--json
For HS256 diagnostics, set the secret in an environment variable and explicitly opt in:
export TOKEN_DIAG_SECRET=<secret>
ALLOW_HS256_TOKEN_VERIFY=true staker-console-v2 verify-token \
--token "$CENTURION_ENROLLMENT_JWT" \
--hs256-secret-env TOKEN_DIAG_SECRET \
--mode strict
The strict HS256 override is required by staker-console/src/commands/verifyToken.ts:53.
Required scope¶
None. This is a local command. It validates token claims and does not use the operator API key.
Backend endpoint¶
None. This is a local command and produces no backend request.
State change¶
None. It reads the token, imports the configured verifier material, checks issuer/audience when provided, and returns decoded verification output from staker-console/src/commands/verifyToken.ts:70.
Error modes¶
TOKEN_VERIFY_CONFIG_MISSING means no Ed25519 public key or allowed HS256 secret was supplied in staker-console/src/commands/verifyToken.ts:43. HS256 in diagnostic mode requires --allow-hs256-diagnostic in staker-console/src/commands/verifyToken.ts:62. Claim parsing errors come from the shared token parser, including missing seat_id, operator_id, sm_url, and numeric timestamp checks in staker-console/src/lib/token.ts:62.