Local execution

sparkwing run runs locally by default. Explicit routing can select a Cloud-owned run hosted on this machine. pipeline trigger submits it to a controller. Both placements use the shared run and job hosts, sealed inputs and matching SDK engine.

Intake and hosts derive plan placement from the sealed request. Local runs, local triggered runs, runner-hosted runs, launcher runs, --runner here and GitHub Actions use the same capability table for initial plans and expansions.

If the pipeline's go.mod replaces the Go SDK, Sparkwing uses the installed CLI's engine and warns that engine pinning is off for that run. The shared installer builds the replacement locally.

Local Go runs reuse their executable while source and captured build inputs match. Reusing the binary skips dependency preparation and compilation. On a miss, Sparkwing resolves imported packages with go list -deps, then hashes the prepared checksums and builds the executable. Preparation uses the build's selected toolchain, workspace and sparks overlay.

The commands bind sealed intake to the shared controller, source, private environment, storage and host services. The CLI sends state operations over the authenticated private API. Owner evaluation delegates a fresh SDK process from the live owner lease. It keeps the evaluated job separate from that lease and creates no work attempt. Each service call rechecks that job's persisted source fence and declared output edges. A separately awarded eval process uses its own eval lease.

The controller claims each executable local job through the shared claim matcher. Each job process receives a fresh credential from its own store-issued node award. The private API preserves the owner and node claim identities so the host can check their relation before starting the process.

Native execution evidence remains with the integration suite. See rewrite integration.

The old pkg/localws server, trigger-consumer election and RunHosted entrypoint are removed with their state, admission, logging and child-dispatch backends. They cannot serve as a fallback for missing native controller or host bindings.

Execution commandsSection anchor link

sparkwing run build-deploy
sparkwing run deploy -- --environment staging
sparkwing pipeline trigger build-deploy --profile prod

Engine flags precede --. Pipeline and job arguments follow it. Local run uses this machine's controller unless Cloud routing is configured. It accepts no connection profile flag. A profile selects the controller for pipeline trigger, run observations and management.

InvocationExecution and records
sparkwing run buildThe CLI hosts the run. The local controller owns its records.
sparkwing run build --sw-detachedThe local controller queues and hosts work independently of the submitting terminal.
sparkwing pipeline trigger build --profile prodThe selected controller queues the run for an eligible runner or launcher.
sparkwing pipeline trigger build --profile prod --runner here --reason repairThis CLI hosts the controller's named here run.

--sw-dry-run records a completed preview as dry_run and exits zero. runs stats counts completed previews separately as dry_run and excludes them from the applied success percentage. A failed or cancelled preview keeps that outcome. Steps run their declared dry-run body or their SafeWithoutDryRun body. Other step bodies are skipped.

--sw-workers N bounds simultaneous local foreground job executions. Jobs waiting for a worker remain available to the scheduler without consuming a local claim. --sw-start-at and --sw-stop-at bound steps inside jobs. Use --sw-only to select jobs and their dependencies.

Ctrl-C requests cancellation and keeps the foreground host alive until the run finishes and logs drain. A second interrupt stops waiting and joins local work.

An explicit empty --sw-cache-from= disables run.cache_from from the machine file. The selected cache profile supplies a temporary repository reader for verified default-branch records to a member with the editor role or above. The credential follows the profile's live membership and revocation and is revoked when the host closes.

--publish P uploads completed local job results, artifacts and retained logs to profile P. Publication creates history with local provenance and no execution claim. A publication error prints a warning and preserves the local verdict. Background local runs publish when their host closes. Published history excludes the private shell environment snapshot, including its variable names and digest.

Local schedule registration, pins, timer installation and __tick use the controller and lifecycle services. Timers carry their absolute state home into resolution. Scheduled execution still needs the scheduler's sealed-intake binding.

Local executionSection anchor link

The local controller owns one home, its SQLite store, admission, queue and browser dashboard. It starts on demand. The CLI hosts a foreground run and sends state operations through the controller API. Its first trigger claim is reserved for that foreground command, so the background queue cannot take it between submission and hosting. Local intake resolves an omitted dispatch to host execution before checking that reservation. Detached submissions enter the background queue. SDK processes declare and execute work through protocol v2. They do not open the controller's database.

Startup reconciles orphaned work and starts the private API before consumers. Readiness does not wait for pipeline compilation or source preparation. The CLI starts or waits for the controller immediately before submitting a run, after source preparation. Other local API commands, doctor and schedule timers use the same startup operation. A startup failure reports why the local controller could not start before any request is submitted.

The controller is the only writer of the shared store. Reads, cancellation, retry and doctor use its API too. The controller's route policy and wire contract also apply to api.sock. A transport retries only operations the registered route marks safe to replay. A lost one-time award is never replayed automatically.

Run listing uses the same public details as single-run status. Filters apply before the page limit. Continuation cursors retain the filters and the initial run-number boundary, so runs created between pages do not displace older runs. Each page checks current authorization and reads signed engine policy notices.

Run and job log reads return tagged JSON pages to the CLI. Each output record names its persisted attempt or owner unit. Resume cursors retain the selection and progress for each subject. An idle follow poll returns no repeated output. Completion requires terminal state and final persisted segments. A cursor never replaces the store's authorization check for those segments.

Cross-run log search uses the same persisted subjects and authorization. Run filters apply before the run limit. A page can contain no matches and still carry a continuation cursor. The cursor keeps the initial run-number boundary and any unfinished subject, so later runs cannot displace older candidates. --max-matches limits each subject. Zero returns all matches across pages.

Who hosts the daemonSection anchor link

The local controller is wingd. These commands inspect or hold its lifecycle:

sparkwing daemon status -o json
sparkwing dashboard start --stay
sparkwing dashboard open
sparkwing dashboard status
sparkwing doctor -o json

Daemon status, stop and restart use the shared local lifecycle. JSON reports state, version, pid, stay, installed and the four activity counts. They report the dashboard apart from the controller: dashboard is serving or not_serving, and while it serves, url is its address. Pretty output prints a dashboard: line either way. A controller that sparkwing run or a schedule started serves no dashboard; sparkwing dashboard open starts one at 127.0.0.1:4343 when none serves, then mints the sign-in link. Once a dashboard has served, a controller that exits idle and restarts on demand serves it again at the same address, until dashboard stop or daemon stop. Stop and restart also report stopped, restarted and previous_version. Plain output is the resulting state. Store and API diagnostics come from doctor. Doctor also sweeps stray step sessions through the controller. A successful cleanup whose run was pruned reports an unrecorded-outcome warning and succeeds.

Restart preserves a stopped controller. An answering controller on the exact installed version stays running unless --force is selected. Replacement waits for shutdown before starting the installed executable with the same home, dashboard address and stay policy. An incomplete drain or unready replacement returns an error without a success receipt.

A client attempts one replacement when it finds an incompatible daemon, including a v0.67 daemon at the socket path used before per-home socket tokens. Startup prints the old and new versions, drains the predecessor and waits for its election lock before starting the selected executable. If an incompatible daemon answers again, stop competing Sparkwing installations and run sparkwing daemon restart, or select a separate SPARKWING_HOME. The replacement still drains active runs before taking ownership.

Active runs, queued triggers, held leases and open dashboard connections keep it alive. Health checks alone do not. --stay keeps it up until stopped. Linux and macOS support an installed login service through dashboard install. Windows supports stay mode. Machine updates refresh managed controller and schedule units together. See local dashboard.

Installation drains and joins the existing owner before activating the managed service, then waits for the successor to acquire the same home and become ready.

Running with no daemon availableSection anchor link

sparkwing run <pipeline> --sw-allow-unadmitted runs the same controller runtime in process for standalone CI. Give it a private SPARKWING_HOME. Its admission queue belongs to that process; it does not join another controller's machine admission queue. It retains run and job concurrency rules. It cannot detach or use Cloud routing. The CLI drains and joins its controller before returning. It must not open a home another controller owns. An unavailable or incompatible shared controller is an error, rather than permission to open its database in a second process. Startup reconciliation and shutdown draining belong to the runtime in both modes.

A local run has no default execution deadline. Queue wait, job execution, approval wait and owner liveness have separate meanings. See limits.

Detaching a run so it outlives the terminalSection anchor link

sparkwing run nightly-report --sw-detached --sw-output json
sparkwing runs status --run RUN_ID
sparkwing runs logs --run RUN_ID --follow
sparkwing runs cancel --run RUN_ID

Detachment queues the sealed request with the local controller. The controller owns consumption and process cleanup. A separate user-managed consumer is not part of the model. A successful submission receipt identifies the allocated run. It does not prove that execution has started.

--sw-idempotency-key gives repeated detached submissions one durable identity. --sw-request-id is a tracing field retained through intake and retry. The detached JSON receipt includes it as request_id. It does not deduplicate work. JSON receipts exclude raw arguments, captured environment values, private bearers and seal hashes. A log path is reported only when it exists.

Making a retry safeSection anchor link

sparkwing run deploy --sw-detached --sw-idempotency-key deploy-2026-10-15
sparkwing runs retry --run RUN_ID --failed
sparkwing runs retry --run RUN_ID --all-jobs

Submission idempotency belongs to intake's transaction. The same key and body return the original receipt. A conflicting body fails. An ambiguous submission does not authorize the caller to invent another run's authority.

A retry keeps the original request, source, captured environment and accepted plan. It records the retrier separately. --failed reuses authorized successful work. --all-jobs executes the complete plan. Application retries within a job keep the same claim and increase the attempt ordinal. Lease loss follows the separate recovery rule in scheduling. When the original plan is already accepted and controller-dispatched, the retry becomes controller-owned during intake. It schedules the preserved plan without starting another planning owner. The controller materializes reused jobs as successful with zero attempts and copies their outputs and artifacts into the new run for dependents. Reused jobs receive no execution claim. If a source result has expired, was deleted or cannot be copied within the retry's data scope, the job executes again.

Publishing a foreground run handleSection anchor link

sparkwing run build --sw-run-handle-file /tmp/build-run.json

The run handle identifies the run for observations and cancellation. It carries no credential. The CLI writes it once at intake with schema_version, run_id and pipeline, and never updates it; read the run's current state with sparkwing runs status --run RUN_ID. --sw-output chooses pretty, JSON or plain output for foreground and detached commands. List commands emit one JSON record per line.

Which checkout runsSection anchor link

Intake seals source identity and the exact commit before execution. Acquisition uses that identity, rather than looking up a branch head again. Repository identity identifies the namespace. It does not grant permission to clone it.

--sw-ref selects the local execution revision. --sw-pipeline-ref selects the pipeline's source revision. A declared pipeline source and an explicit pipeline ref must agree. Resume and retry use the persisted selection. They do not replace it with the caller's working tree or current machine settings.

Both flags resolve before inspection and building. The selected execution checkout supplies the project configuration. Its configured entrypoint selects the SDK declaration, while pipeline code can come from the separate source revision. Trigger inspection uses the same execution and code commits as hosting. A local schedule resolves pins such as source: origin/main before sealing each run. The pipeline alias remains in run context and output.

A source: pin that is a full commit ID keeps the run's sealed identity. A branch or tag pin, such as origin/main, runs code whoever can push that ref chooses, so unless it resolves to the execution commit itself the run is sealed as asserted: its OIDC token claims trigger:manual with no ref or sha, it receives no reserved pool, and it writes under its own fetched cache scope. It still reads its repository's pipeline secrets and its token still claims repository_id, because the controller fetches its code from the repository; see secrets. Pin a full commit to keep an App, schedule or Actions run's identity. See OIDC.

The pinned Go or TypeScript SDK selects its matching verified engine before SDK installation, describe, planning or execution. Each machine fetches that release once from GitHub Releases and verifies it. Pipeline binaries are built and cached on the executing machine. Local execution does not fetch prebuilt pipeline binaries from a controller. See repository upgrades. For an uploaded Go pipeline, the runner installs the SDK from the acquired snapshot before planning. An upload with a local SDK replacement must include that replacement's source.

Before a local run is accepted, foreground and queued hosts select Go or TypeScript from the sealed checkout's pipeline directory. A malformed manifest fails setup. Accepted runs retain the SDK identity in their sealed engine.

SDK describe, plan, eval and attempt processes run from the acquired checkout root. If describe fails before secret declarations are known, the diagnostic names the error code and withholds the details because they may contain secrets.

Remote executionSection anchor link

sparkwing pipeline trigger deploy --profile prod --detach -- --environment staging
sparkwing runs status --run RUN_ID --profile prod
sparkwing runs logs --run RUN_ID --profile prod --follow

The command prepares one sealed request and submits it to POST /api/v1/runs. Detached output includes the stable run ID, team number and replay flag. Preparation failures submit nothing. The old trigger request and separate here-host loop are removed.

--ref selects the execution commit. --pipeline-ref selects the pipeline commit, subject to any configured source pin. That pipeline commit's package.json determines Go versus TypeScript before source acquisition and engine selection. A different SDK in the working tree or execution commit cannot change the selection. A malformed selected manifest fails preparation.

GitHub numeric-ID lookup, private source access and captured environment delivery still need their native bindings. Initial here intake refuses before submission until its reason can survive the sealed request and replay.

The selected controller owns the run's records. Its intake derives the caller's authority. A runner claims trigger and job units through one ordered queue. The launcher creates Jobs for awarded plan, eval and work units. Both use the shared matcher and hosts. Inline jobs stay with the run host.

The working-tree option submits an immutable source snapshot. Secret-shaped files require explicit review through the allowed-file option. Keep credentials in ignored files or outside the repository and inspect git status before submission. Trigger and burst scan the final bundle for configured local secret values before uploading it through the controller's signed storage binding. The scan includes every object payload and the transported metadata, including file names, commit and tag messages, refs, unchanged files and bundled history.

Here execution retains its one-time authority in an owner-only controller/run record before hosting. Resume takes only the run selector and connection:

sparkwing pipeline trigger deploy --profile prod --runner here --reason repair
sparkwing pipeline trigger --resume RUN_ID --profile prod

The named claim supplies the original request and accepted plan. The first interrupt asks the controller to cancel while the host keeps renewing and draining. A second interrupt stops hosting and observation, then joins both. Incomplete hosting or observation exits 3. See here execution.

Hosting closes returned session resources before exiting, including when a binding fails after allocating them. A cleanup failure remains an incomplete handoff and preserves the binding or execution error.

Local and here hosting use the earliest of the caller's deadline, the award's binding deadline, the owner deadline and the parent capability's expiry. Expired authority stops before host binding. Binding and hosting share that context. The host receives a copy of the awarded runner identity, so binding cannot change its labels.

Team runners fetch source themselvesSection anchor link

Source acquisition clones the sealed SHA directly from the authorized Git host. An optional source bundle seeds acquisition. No cache mirror or package proxy sits between the runner and origin. Source credentials require live claim authority. A repository name alone grants no source access.

What a laptop runner trustsSection anchor link

A runner executes accepted repository code as its OS user. Its private credential file keeps accidental disclosure out of configuration and output. Code running as that same user may still read it and other files in the account. Use a dedicated OS account, container or VM and enroll only repositories whose code may use that account's permissions.

Runner repository restrictions, granted reservations and resource capacity filter claims before preferences order eligible work. Labels grant no pool membership or repository permission. See scheduling, Git credentials and the threat model.

Environment and secretsSection anchor link

A local run captures its environment once. Children retain its captured snapshot when their invocation source becomes a child run. Submitted remote values use separate encrypted storage. Children inherit the parent's environment source, and schedules capture theirs at installation. The daemon's ambient environment never replaces accepted values. The sealed spec records names and a digest. Values remain in private host storage.

Shared process policy filters every spawn. Remote submission passes only the minimal base, network/CA settings and explicitly allowed names. Credential-shaped names remain excluded even when allowed. Proxy credentials are the passed and masked exception. Capabilities, bootstrap values and protocol handles travel in private files, memory, pipes or argv as specified by their contracts, never env.

Job startup settings are projected before process creation. Body and cleanup receive the same complete attempt environment. A changed replan fails as plan_drift. Secret arguments stay available to execution but are redacted from previews, receipts and diagnostics. See environment variables.

Authorization modelSection anchor link

Local and remote controllers enforce the same route policy. Team authority, repository access, job bindings and claim liveness come from authenticated server facts. A management credential cannot substitute for the current execution holder. Public run details are redacted projections, not executable inputs.

An awarded host retains its selected controller transport for private execution state, source credentials and storage. These controller API calls use the award's capability. The runner's reusable claim credential stays with the claim loop.

The controller logs each HTTP server failure once with its request ID and masked cause. Match the response’s X-Request-Id to the controller log to investigate a generic client error. Unmatched routes log the method and sanitized path with the 404 response. The path excludes query parameters and masks registered secrets and credential selectors.

The laptop boundarySection anchor link

The local controller authenticates its OS account. Unix sockets require private ownership and kernel peer credentials. Windows uses the account SID. An unauthenticated or foreign peer is refused. The dashboard's TCP listener needs a bearer session from a one-time link that sparkwing dashboard open mints over the socket; no cookie is used. The link works once within 60 seconds, and the browser tab then acts as the socket peer that minted it until 12 hours pass without a request, 24 hours pass since sign-in, the tab logs out, or the controller restarts. There is no separate dashboard store. Root and same-account code remain inside the machine trust boundary. See security.

Per-host concurrencySection anchor link

Admission arbitrates local CPU and memory. Concurrency groups coordinate declared work through the controller. Neither is a credential boundary. Inline placement keeps work on its run host without a reserved-label alias.

sparkwing queue list -o json
sparkwing queue priority --run RUN_ID --set front
sparkwing runs stats --sizing

Missing observations remain missing. They are never rendered as zero capacity. An unavailable controller returns an error. See admission and diagnosing admission for measurements and queue views.

Capping sparkwing's share of the machineSection anchor link

Set the machine budget in the private machine file:

admission:
  budget: 50%,enforce

Admission charges against that host's capacity. On Linux, an available writable cgroup can enforce the machine budget. macOS scheduling controls are advisory. Runner labels control job placement, rather than an OS resource sandbox. Operator ceilings refuse excessive author values instead of silently clamping them. See machine settings.

Windows with Git BashSection anchor link

Go and TypeScript are supported on native Windows. Git Bash supplies Bash and shell utilities, while pipelines still need native tools for the commands they execute. Use node.exe to invoke JavaScript command entrypoints.

Windows process cleanup uses kill-on-close Job Objects. Unix uses owned process sessions. Native Windows handle inheritance, cleanup and SDK execution require Windows acceptance runs. Linux fixtures and cross-compilation do not establish those behaviors. See node protocol.

Burst and overflowSection anchor link

Configure a Cloud connection and opt in through machine run.routing. The machine file alone selects the route, profile, preferences, local secret sources, overflow limit and untracked source files. Repository configuration can restrict execution to this machine and declare required secret names.

run:
  routing:
    route: cloud
    profile: work
    prefer:
      - target: here
        hold: 5s
      - target: machines
        hold: 10s
      - target: cloud
    local_secrets: [DEPLOY_TOKEN]
    source_files: [generated/fixture.json]
    overflow_minutes: 120

The route defaults to local. The example gives this machine the first chance, then the user's registered personal machines, then Cloud. Holds apply while an eligible preferred claimant is live. An absent claimant does not delay later capacity. Omit prefer to use here for five seconds, machines for five seconds, then cloud. name=NAME selects a registered machine by name. Named and pool selectors can narrow the requester's eligible personal machines. Cloud executors require a cloud entry. Runners outside the sealed preference set cannot claim burst jobs or read requester secrets, even after all holds expire. Team runners remain excluded. The attached here owner retains its planning authority.

Repository restrictions apply to machine-authorized routing. For example, keep deployment on this machine:

pipelines:
  - name: deploy
    entrypoint: Deploy
    run:
      route: local

Cloud owns the run record. The invoking CLI hosts its scheduler, streams logs and requests cancellation on Ctrl-C. The first interrupt keeps the owner alive until local and remote jobs finish cancelling. Secret reads remain refused during this drain. A second interrupt stops hosting. Nodes use the existing claim, lease and fencing rules. The local controller supplies this machine's admission only. Other machines register as runners with Cloud. They need sparkwing-runner beside sparkwing, which curl -fsSL https://sparkwing.dev/install.sh | sh -s -- --runner installs from the signed release. sparkwing runners add --runner NAME --personal --session-stdin --profile work reads an existing independent account session from stdin and reserves the machine for that user's asserted runs. Omit --repos for a personal runner. Repository scopes require proven code, which personal machines never claim. The session and its CSRF proof stay in memory. After fetching the proof, the command attempts logout on enrollment success or failure and saves only the new runner credential. Use a dedicated session because logout ends it for every client. A profile backed only by a member token cannot enroll a personal machine. The team's members_can_add_machines setting defaults to true. Any member can enroll a personal machine while it is on. When it is off, personal enrollment requires team administration. Shared runners always require team administration to enroll, mint tokens for or revoke.

Administrators change this setting in the console's team settings or with sparkwing team settings set --profile work --members-can-add-machines false. sparkwing team settings show --profile work reads it. Changes are audited. Turning the setting off ends the personal machines that members without administration enrolled, and turning it back on does not revive them: those members enroll again. Administrators' own machines keep working.

A personal machine takes your own runs that select no runner, ranked under the team's claim ranking. A run you trigger from this machine ranks it here. Runs started by a push, pull request, release or schedule never reach it.

Cloud routing requires an attached terminal session. The default local route continues to support --sw-detached.

Registered machines advertise labels and a configured concurrent-job count. Required labels select eligible machines. CPU and memory observations are not claim requirements. Enrollment can enable local_admission to share the machine's local admission controller with local runs; claim authority and placement still belong to the controller. With local_admission enabled, a registered machine with no available local CPU or memory budget withdraws its job capacity until budget becomes available. Planning continues while the machine budget is full.

Each claimed job holds its machine lease through source preparation, execution and cleanup. Busy local work does not prevent jobs from becoming ready for overflow. The store commits plan capacity with permission to release work. Each executing host requests its complete job group set under its actual award before compute. Scheduling holds no compute while logical admission waits. The requester takes a provisional burst award only when its local ledger shows available CPU and memory budget. While that budget is full, the here owner leaves jobs ready for Cloud or another eligible machine. If the ledger cannot be read, normal admission decides whether the job can start. After taking an award, the requester takes logical admission, then tries compute without waiting. If compute is unavailable, it returns the award and job reservations. The original readiness ranking window survives, so other ranked claimants can take the job. Ctrl-C cancels the wait. Concurrency slots count once even when a registered runner shares this machine with the requesting CLI. Machine admission keeps Cloud run identities separate from local records. Cloud overflow captures the working tree. Use pipeline trigger for explicit committed revisions instead of --sw-ref or --sw-pipeline-ref.

An unreachable controller before intake, including connection setup and source upload, produces a message and a local run. Authorization failures remain errors. After intake, a lost response or connection cannot start a second local run because the admitted run keeps its Cloud owner.

The source bundle contains Git-tracked files with their working-tree edits and deletions. Untracked files require their exact repository-relative paths in machine run.routing.source_files. A repository source_files declaration requires that machine approval, including for ignored paths. The bundle has no parent history. Secret-shaped files are refused before upload. The local secret scan checks every included object and source metadata, skips values shorter than eight bytes and ignores PEM armor lines. Log masking keeps its full patterns. Trigger and burst upload the private copy that passed the scan through authorized content-addressed source storage. Each executor prepares its private source workspace on first use and builds the pipeline from the uploaded snapshot with its selected engine. Go installation downloads the dependencies used by the pipeline.

Jobs publish declared artifacts through the same storage path on this machine, on a personal runner and in Cloud. A dependent job's Consumes declaration restores the producer's files into its workspace, including across machines. A missing or corrupt artifact fails the consumer.

Declared dependency caches restore before the job and save successful cold directories through its current storage authority. This applies here, on personal machines and in Cloud. Package-manager cache paths use the persisted job environment. Jobs share matching dependency caches within the same repository and ref, while every write retains its originating job attempt for authorization. Cache transfer failures warn and leave the next job to run cold.

Cloud allocates the CPU class selected by the team's price table and the memory that comes with that class. This also covers jobs without explicit resource settings. The allocation stays fixed for the award if prices change or bootstrap authority is exchanged. Team standing and your overflow allowance still control new Cloud admissions.

pipelines:
  - name: test
    entrypoint: Test
    source_files: [generated/fixture.json]

Declare secrets in the pipeline, then authorize the names to resolve locally in machine run.routing.local_secrets. Repository run.local_secrets lists names only and cannot select requester sources or supply values. Machine secret classification also remains in force for local snapshots. The CLI reads those names from its captured environment at intake. Required missing values fail before submission. Other declared names use the team's normal secret provider; a run of a local checkout or working tree reads only its team's --shared secrets, never a repository's pipeline secrets. Values travel outside the sealed request and bundle, stay in controller memory, and are released only to the live claiming process with masking enabled. The attached here host re-supplies values on authenticated owner heartbeats and when it resumes after a controller restart. Team deletion, terminal completion and owner lease expiry purge those values. The Cloud chart supports one controller replica and uses a Recreate rollout. Run intake, plan validation and secret release reach that same process. Multiple controller replicas require an ephemeral secret relay or verified run affinity before they can support requester-resolved secrets. Retry also requires a fresh submission so values can be resolved again.

Local routing and offline fallback resolve the same configured names at intake. Those environment entries are excluded from the saved local environment snapshot. The local controller releases their values through the same masked, volatile secret path.

There is no per-user overflow cap by default. overflow_minutes narrows the user's monthly Cloud allowance for this run. The account's saved limit can only be tightened by the request. Read and change your saved allowance with:

sparkwing overflow show --profile work
sparkwing overflow set --profile work --minutes 120
sparkwing overflow set --profile work --minutes 0
sparkwing overflow set --profile work --uncapped

Zero prevents new Cloud overflow. --uncapped removes your saved cap. Use -o json for the saved monthly_minutes, used_seconds and UTC period_start. GET /api/v1/overflow reports monthly_minutes, used_seconds and the UTC period_start. PUT /api/v1/overflow saves {"monthly_minutes":120}, and {"monthly_minutes":null} removes the saved cap. These operations use the selected account credential. Team standing tiers and the prepaid balance still apply. Once the allowance is reached, new Cloud claims wait while local and registered-machine capacity remains eligible. Each lease renewal of running Cloud work reserves more time only while it fits the allowance. A job the allowance cannot extend keeps the time it already reserved, then is cancelled with the reason monthly overflow allowance reached. Deleting run history keeps its usage in the monthly total.

Local publication has a 45-second request deadline. During publication, a second Ctrl-C abandons the upload and reports that the run stayed local-only. Publication failure preserves the local execution verdict. Published history never replaces the team's latest successful execution pin.