Repository navigation
Split the Core/Web boundary: official /v1, one Core-key /core/v1 tree, Core-key executor credentials - #128
Merged
Conversation
/v1 now has the 58 method and path pairs of the pinned OpenAI Python SDK 3.13.0. The eight Core extension routes are removed from /v1: startup configuration, Runtime observations (list and per Session), Runtime history (capabilities and per Session), Session execution configuration, Session sandbox placement and the sandbox node directory. Their administrator equivalents under /core/v1/admin keep the same handlers. Placement is automatic only: x_agents_core.sandbox_node_id is removed and is now rejected as an unknown member (400). The store no longer selects an explicit node, and the unused per-Session placement read is gone. The shared client drops SandboxProjectClient and the public /v1 readers for the removed routes; AdminClient keeps its /core equivalents. scripts/extract-agents-api-upstream.py writes upstream-routes.json and upstream-fields.json from the pinned SDK. Contract tests require the public OpenAPI to have exactly those routes and to keep every non-official field inside x_agents_core, with three shared-schema mismatches listed for a decision.
Port the ordering, concurrency-limit and whole-page failure tests of the removed /v1 list to GET /core/v1/admin/runtime-observations, including its Project labels and tenant binding.
The field audit now accepts x_agents_core only on the Agent, saved-Agent and Session definitions, with harness and model_provider as its only members, and compares query parameters with the SDK's query params types, which the extractor now records. A test proves the audit catches sandbox_node_id in the Session or Agent extension and x_agents_core on a Vault, and the extracted operations must equal the pinned route set. The router walk compares the served non-HEAD /v1 routes with the pinned set. Administrator Runtime tests cover the unconfigured 503 and HEAD 405, and the client tests cover the observation page invariants. Docs no longer mention explicit node selection or Project node reads, say when a Session carries agent.x_agents_core, list executor credential issuance in the API index and drop the removed /v1 Runtime reads from the HEAD exceptions.
…ry-p2b # Conflicts: # contracts/agents-api/admin-api.md # contracts/agents-api/sandbox-manager.openapi.yaml # services/agents-api/internal/api/admin_resources.go
…thout a route P1 removed their /core/v1/admin routes and P4 removed their /v1 routes, so after the merge the handlers, Core types, server composition, client projections and tests had no caller.
/core/v1/admin/** moves to /core/v1/**: projects, summary, audit-log,
metrics (was core-metrics) and sandbox/runtime-observations. One
Core-key router serves the whole tree, so every /core/v1 request,
including an unknown path, is authenticated before routing, and old
/core/v1/admin paths return 404.
Executor credentials move from the Project-key route
/core/v1/environments/{id}/executor-credentials to
/core/v1/projects/{project_id}/environments/{environment_id}/executor-credentials
with the Core key: GET lists metadata, POST issues or rotates, DELETE
revokes. The target must be a self_hosted Environment of the Project whose
Session exists. The Project's principal remains the execution principal,
the scope stays daemon enrollment and connection for that Environment, and
each write records an administrator audit entry in its transaction.
…re key The per-route allowlists in admin_routes.go and sandbox_admin.go and the /core/v1/environments special case are replaced by one rule: after console sign-in and the existing origin and CSRF checks, a /core/v1/* request is forwarded with the Core key and Core decides whether the route exists. /v1 and /api/v1 still return 404, and the path checks that keep dot segments and encoded separators from leaving /core/v1 are unchanged.
AdminClient, SandboxAdminClient and CoreMetricsClient keep their names and methods but no longer extend the /v1 OpenAIAgentsClient. They share an internal Core request layer that reuses AdminClient's error projection and AgentCoreError, never sends OpenAI-Beta and sends a bearer only when a Core key is given. Defaults are /core/v1, /core/v1/sandbox and /core/v1/metrics; listRuntimeObservations reads /core/v1/sandbox/runtime-observations. Export CoreProjectReader as agreed with Web, tighten listSkills, listSkillVersions and listSourceFiles to SkillList, SkillVersionList and SourceFileList so a project-bound AdminClient satisfies it without a cast, and add listExecutorCredentials, issueExecutorCredential and revokeExecutorCredential with ExecutorCredential, IssueExecutorCredentialInput and IssuedExecutorCredential. SandboxNode.diagnostic is optional because Core omits it when ready.
sandbox-manager.openapi.yaml held every /core/v1 route, not only sandbox administration. make openapi now splits the generated document by namespace into openapi.yaml (/v1), core.openapi.yaml (/core/v1) and runtime.openapi.yaml (/api/v1); the public openapi.yaml is unchanged.
A table over the served composition shows a Project API key reaches only /v1, the Core key only /core/v1, and node and executor credentials only their own /api/v1 machine connection routes; every other cell is 401.
AGENTS.md is replaced with the agreed draft adjusted to the final facts. docs/api/README.md becomes the /v1, /core/v1 and /api/v1 table with a /core/v1 route-group index; CONTRIBUTING.md, design principles, the Web and public API guides and getting-started describe Web as a /core/v1-only client behind a prefix proxy. Contracts move from /core/v1/admin to /core/v1, the executor credential contract and self-hosted installation steps describe Core-key issuance by the operator, and the removed startup configuration and history capability reads are noted.
…125) Keep #124's Core-key sign-in, fixed console actor label and configuration names; the console still forwards every signed-in /core/v1 request by the prefix rule instead of the removed allowlists. Installer, console tests and docs take #124's wording with /core/v1 paths in place of /core/v1/admin. #123's allocation test uses automatic placement, since P4 removed explicit node selection.
A key_id that is not a canonical lowercase, non-nil UUID is 400 before any store call, and rotate:true for a key_id that was never issued is 404.
Issue and rotate return the existing 409 project_archived. The check share-locks the Project inside the issuing transaction, before the write and its audit entry, so a concurrent archive either follows the issuance or is seen by it. Listing and revocation stay available, because revoking must always work.
The generated Core contract described its operations as deployment administrator only; it now names the Core key, as the docs do, and says the Project ID, not a key, selects the target space. openapi.yaml is unchanged.
Issue and rotate now validate the request body (400), then the target Environment (404), then an archived Project (409 project_archived), and only then the key: 409 executor_credential_exists without rotate, or 404 for rotating a key_id that was never issued. Previously the Project was resolved before the body, and rotation checked the key before the archive. The in-transaction archive check stays for concurrent archives.
The Core-key POST under /core/v1/projects/{p}/environments/{e} is now the
instruction; keys.json no longer exists. agents-api-environment-key remains
only as a marked break-glass database path that skips the archived-Project
check and writes no administrator audit entry.
The default is now /core/v1 and the client requests /metrics?range=..., so new CoreMetricsClient() still reads /core/v1/metrics. Option names are unchanged; each option has a one-line doc comment.
An unconsumed enrollment token reads node configuration and gets 401 on /v1, /core/v1, node identity and both agent-daemon routes. The matrix now also covers daemon enrollment, which only the executor credential passes.
It was the last Core operation tagged "Core extensions"; it is now "Execution configuration", beside "Runtime observations" and "Runtime history". Project resource summaries say "in a Project" instead of the stale "in a managed key space". openapi.yaml is unchanged.
Rotating a key_id never issued for the environment returns 404, key IDs must be lowercase non-nil canonical UUIDs, and not-found responses use Core's not_found_error code.
Core refuses issue and rotate on an archived project with 409 project_archived while list and revoke still work. The fixture returns that 409, and the Session page hides Issue and Rotate with a note; a write that meets project_archived shows the same note as its error and rereads the projects instead of entering rotate recovery.
A kept key ID from an issuance with an unknown outcome is no longer sent again once it is listed, and a successful rotation or revocation of it forgets it, so the next Issue starts a new credential instead of offering to rotate one that was just rotated or revoked. An existing key ID (409) opens rotation only after a fresh read shows it active in an active project; otherwise the issuance is reported as rejected. Dismissing the one-time credential dialog now keeps the credential on the page until Done, as the API-key flow does. The list's date column is "Created", and the empty state no longer repeats the Issue button.
Core accepts the self_hosted environment of any existing Session in the project and returns 404 otherwise; its only conflicts are project_archived and executor_credential_exists, and rotation restores a revoked key, which the console hides by choice. Record the archived-project view, the recovery rules and the Session page's credential management.
This was referenced Sep 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Completes the Core/Web API boundary as a single paired release (backend P2b and P4, plus the Web P2b from #127):
/v1is exactly the pinned official Agents API. It serves only the pinned SDK route set. Non-official request and response fields live only underx_agents_core(harness,model_provider). The eight extension routes andsandbox_node_idare gone. Route-set and field-placement tests hold this in place./core/v1is one Core-key tree for the Web and operator scripts. The/adminsegment is dropped:projects/**,summary,audit-log,metrics, andsandbox/{deployment,enrollment-tokens,nodes,runtime-observations}. Authentication runs before routing, so unknown paths and 405 responses also require the Core key. A Project key gets 401 everywhere under/core/v1, and the Core key gets 401 on/v1and/api/v1.GET/POST/DELETE /core/v1/projects/{p}/environments/{e}/executor-credentials[/{key_id}].project_archived→ existing key 409executor_credential_exists/ rotating an unknown key 404.FOR SHAREagainst the archive'sFOR UPDATE).Cache-Control: no-store.services/core-consoleforwards every signed-in, same-origin/core/v1/*request with the Core key. It no longer uses per-route allowlists.safePathrejects encoded%, dot segments, empty segments and backslashes.console.packages/agents-clienthave their own/core/v1request layer and no longer inherit the/v1client. The package exportsCoreProjectReaderand the executor credential types, andCoreMetricsClient.baseUrlis now a prefix./core/v1contract is generated ascontracts/agents-api/core.openapi.yaml.openapi.yamlcovers only the pinned official routes./v1,/core/v1,/api/v1), and the release guide now issues executor credentials with the Core key. The database command is kept only as break-glass.Review
Verification
f9b145c6 (the exact head of this PR): passed. It coversmake checkplus typecheck, core-doctor, the Web unit tests and the Web build.openapi.yaml,core.openapi.yamlandruntime.openapi.yamlproduces no diff./core/v1paths serve, the old paths return 404, a Core-key-issued executor credential lets a real daemon connect, and after revocation the daemon is refused.agents-apijob timeout also occurs on main and is tracked for a follow-up.Compatibility
/v1extensions or the old/core/v1/admin/**paths. No product code depends on them yet./api/v1/sandbox-node/*(Move node transport to /api/v1 and stop forwarding it through Web #119). A demo drain from a pre-spec deployment must still use a pre-P3 build.Need help on this PR? Tag
@codesmithwith what you need. Autofix is disabled.