## Task
Help the caller choose a source, confirm, and start exactly one Standard Apex
security scan for this repository through the hosted REST API. As soon as Apex
accepts the scan, return the workspace ID, scan ID, accepted status, and direct
links. Do not wait for the scan to finish, poll it, or fetch findings in this
task. Never offer or start an Audit or Lite scan.
## Integration boundary
- Use the Apex service API documented at https://ai.cantina.xyz/docs/apex-api.
- Do not install or invoke Apex CLI or MCP.
- Do not run `apex login`; CLI device authentication does not accept service
keys.
## Preconditions — check before doing anything else
1. Check only whether `APEX_SERVICE_KEY` is set and non-empty.
- If missing or empty, stop immediately and report that
`APEX_SERVICE_KEY` is not defined.
- Never print, echo, log, serialize, or include its value in an error.
- Do not inspect or print `CANTINA_API_KEY`; this workflow does not use it.
2. Confirm the key is intended to have `scans:create`. If the API returns 403,
stop and report that the key lacks the required scope.
3. Read the current API documentation before making requests. If it conflicts
with this prompt, follow the documentation and report the difference.
4. Call `GET /api/apex/v1/credits` with the service key.
- If `scansEnabled` is false, stop and report that scans are disabled for
the organization.
- Retain `balances.standard` and `scanTypes.standard` in memory. Do not use
CLI/MCP or ask the caller to supply balances.
- Treat `scanTypes.standard.available` as a point-in-time credit check. The
accompanying `ledger` and `creditsRequired` explain the Standard balance
that will be charged.
- Ignore Audit and Lite availability. This workflow never offers those scan
types even when they have available credits.
## Choose before creating anything
1. Inspect the checkout without modifying it. Determine the repository
directory name, full HEAD commit SHA, Git remote, and whether the checkout
is clean and its HEAD commit is available from the GitHub remote.
2. Build the compatible choices below. Never show a source-incompatible choice.
Apply the credit response before presenting the list.
- `standard` + `local_archive`: available when
`scanTypes.standard.available` is true, for the exact local checkout,
including dirty, unpushed, non-Git, or non-GitHub source.
- `standard` + `remote_repo`: available only for a clean, provider-backed
GitHub commit that Apex can materialize and when
`scanTypes.standard.available` is true.
- If no compatible funded choice remains, report the Standard remaining
balance and stop without creating anything.
3. Present one concise selection question. State that the scan type is fixed to
Standard. For each choice show the source mode, effective ledger, credits
required, and that ledger's remaining balance. Explain that a local archive
scans the exact checkout, while a remote scan uses the named commit. Ask:
`Which Standard scan source should I use?`
- Do not create an archive, upload, workspace, or scan before the caller
chooses.
- If only one compatible choice remains, ask the caller to confirm it.
- If the caller already selected a compatible source mode in the same
request, summarize the Standard scan choice and treat it as confirmed.
## Start the confirmed scan
### Local archive choice
1. This source supports only `scanType: standard`. Create a temporary `tar.gz`
archive outside the source tree without modifying tracked files.
2. Calculate the archive SHA-256, compressed byte count, and uncompressed byte
count required by `POST /api/apex/v1/source-uploads`.
3. Create a source-upload session using the repository directory name as the
workspace name. Retain the workspace ID, upload ID, signed PUT URL, and
required upload headers in memory. Treat the signed URL as a credential.
4. PUT the archive to the signed URL using every returned header. Then call
`POST /api/apex/v1/source-uploads/{uploadId}/complete` and retain its archive
ID and verified SHA-256.
5. Build the scan request with the workspace ID, `scanType: standard`,
`generateThreatModel: true`, and one `local_archive` scan source containing
the archive ID and verified SHA-256. A new local workspace has no model to
reuse, so do not omit `generateThreatModel: true`.
### Provider-backed choice
1. Use the canonical GitHub repository URL and full HEAD commit SHA. Do not use
a moving branch or tag.
2. Build the scan request with `scanType: standard`, `repoUrl`, `commit`, and
`generateThreatModel: true`.
3. If workspace resolution returns 409 with multiple matching workspaces, show
those choices and ask which workspace to use. After selection, include its
`workspaceId` and use a new idempotency key because the first request had a
definitive 4xx response.
### Submit and hand off
1. Generate one stable idempotency key for this intended scan. Call
`POST /api/apex/v1/scans` with the confirmed request.
2. After a successful HTTP 202 response, retain the workspace ID from source
setup, workspace resolution, or the accepted response, plus the returned
scan ID, status, `statusUrl`, and `findingsUrl`.
3. Resolve relative API URLs against `https://ai.cantina.xyz` and construct:
- Workspace link:
`https://ai.cantina.xyz/workspace/<workspaceId>`
- Scan link:
`https://ai.cantina.xyz/workspace/<workspaceId>?scanId=<scanId>`
4. Delete only the temporary local archive, if one was created. Do not modify
repository files.
5. Return the handoff output immediately. Do not call the status or findings
endpoints, wait for a terminal state, or create `apex-findings.json`.
## Credit and error UX
- On 402, report that the Standard scan credit is unavailable. Do not submit
another scan. Refresh `GET /api/apex/v1/credits`; if Standard is available,
re-present the compatible source choices and require confirmation. Otherwise
report the remaining Standard balance and stop.
- On 403, report the missing `scans:create` scope.
- On a workspace-resolution 409, ask the caller to choose from the returned
workspaces; do not guess.
- On an active-scan or other 409, report the conflict and stop rather than
forcing or duplicating work.
- On an unrecoverable error, report the HTTP method, endpoint path, status, and
redacted response body.
## Retry and safety rules
- Send `Authorization: Bearer <service key>` without logging the header.
- Credit-balance GET requests are safe to retry with bounded backoff.
- Reuse the same idempotency key and identical request body only after a
transport error, timeout, or 5xx from scan creation.
- After correcting a definitive 4xx, use a new idempotency key.
- Never change source mode or workspace without caller confirmation. The scan
type must remain `standard`.
- Never create a second scan merely because a request timed out or the client
restarted.
- Do not improvise CLI commands or alternative authentication flows.
## Output
Return immediately after HTTP 202 in this shape:
Apex scan started
- Scan type: standard
- Source mode: <local_archive|remote_repo>
- Workspace ID: <workspace-id>
- Scan ID: <scan-id>
- Accepted status: <status returned by Apex>
- Workspace: https://ai.cantina.xyz/workspace/<workspace-id>
- Scan: https://ai.cantina.xyz/workspace/<workspace-id>?scanId=<scan-id>
- Status API: <absolute-status-url>
- Findings API: <absolute-findings-url> (available after completion)
Do not include elapsed time or finding counts because this task does not wait
for completion.