Skip to content

feat(tools): let components launch admin tooling, starting with StackPort for LocalStack - #72

Merged
martypitt merged 2 commits into
mainfrom
spike-stackport
Sep 26, 2026
Merged

martypitt merged 2 commits into
mainfrom
spike-stackport

Conversation

@martypitt

Copy link
Copy Markdown
Contributor

Summary

Components can now offer tools: a browser or admin console for the thing they run, launched on demand from the management UI. The first one is StackPort for the LocalStack-backed components (S3 and API Gateway).

On a running component, Tools → Launch starts the tool. Once it's up, Open opens it in a new tab.

How it works

  • ProvidesTools (nebula-dsl): a component describes each tool as a container spec: image, env, port and readiness path. The component fills in the coordinates and credentials because it knows them. Nothing in the runtime is AWS-specific. Kafka (kafka-ui), SQL (pgweb/Adminer) and Mongo (mongo-express) could use the same contract.
  • ToolRunner (owned by StackRunner):
    • launches tools on the Nebula network and maps their port to the host
    • stops a tool when its component stops, for any reason, or when the stack shuts down
    • sends tool logs to the stack's Logs tab
    • Tools don't count toward stack state.
  • StackPort is pinned to davireis/stackport:0.4.4 and pointed at the component's LocalStack container, using that container's credentials and region.
  • Admin API:
    • POST /api/stacks/{id}/components/{componentId}/tools/{toolId}/launch returns straight away with the tool Starting.
    • POST /api/stacks/{id}/components/{componentId}/tools/{toolId}/stop.
    • AdminStackView gains tools: each running component's tools and their state.
    • The Orbital-facing /stacks API is unchanged.
  • UI:
    • a Tools menu on each component, and a Tools section in the expanded panel
    • The URL uses the host the UI was loaded from, so it works when Nebula runs on another machine.

Network alias collision

Stacks share one Docker network, and components use their name as their network alias. Two stacks that each have an s3 component both answer to s3. In testing, StackPort showed the other stack's buckets. Tools now reach their component by its IP on the network, through a new uniqueNetworkHost helper. Container names didn't work: Docker's generated names contain underscores, which the AWS SDK rejects in endpoint URLs.

The same collision still affects NETWORK-mode consumers (Orbital in compose is given s3:4566). That predates this PR and isn't fixed here.

Also included

070017c feat(apigateway): give each REST API a stable id across stack restarts was committed after #71 merged and was never pushed, so it's on this branch too.

Test plan

  • ComponentToolsTest (new, runs against real containers):
    • launches StackPort against an S3 stack and reads the buckets through it
    • launching twice is a no-op
    • the tool stops with its component
    • with two stacks that each have an s3 component, StackPort shows only its own stack's buckets
    • refuses to launch on a stopped component
  • Existing S3ExecutorTest, ApiGatewayExecutorTest, StackRunnerResubmissionTest, StackStartFailureTest and NebulaServerTest pass
  • Manual run in the UI: launch from the Tools menu, open StackPort, see the stack's buckets
  • First launch when the image hasn't been pulled yet: the UI shows "Starting…" with no pull progress

🤖 Generated with Claude Code

martypitt and others added 2 commits September 23, 2026 00:20
importRestApi minted a fresh id on every start, so anything that had
recorded an id (an Orbital registry selection, an env variable pasted
into a config file) broke each time the stack restarted. Create the API
first with LocalStack's _custom_id_ tag, defaulting the id to the
declared name in lower case, then import the spec into it with
putRestApi. An explicit apiId can be given.

Also documents that response schemas must be named models: API Gateway
drops inline schemas on import, and the export then has operations with
no response schema.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011c7t8dqC37eQzTt9o44x9v
…Port for LocalStack

Components can now offer tools - typically a browser / admin console for the
thing they run - that are launched on demand from the management UI.

- ProvidesTools: a component describes each tool as a container spec (image,
  env, port, readiness path). It fills in the coordinates and credentials,
  since it's the one that knows them.
- ToolRunner (owned by StackRunner) launches tools on the Nebula network,
  maps the port, and stops them when their component stops or the stack
  shuts down. Tool logs appear in the stack's logs.
- S3 and API Gateway offer StackPort (davireis/stackport:0.4.4), pointed at
  their LocalStack container.
- Admin API: POST /api/stacks/{id}/components/{componentId}/tools/{toolId}/launch
  and /stop. The admin snapshot includes each running component's tools.
- UI: a Tools menu on each component, plus a Tools section in the expanded
  panel. The URL is built from the host the UI was loaded from.

Tools reach their component by its container IP (uniqueNetworkHost), not the
network alias: stacks share a network and can reuse component names, so an
alias like `s3` can resolve to another stack's container.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@netlify

netlify Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for orbital-nebula ready!

Name Link
🔨 Latest commit 6812fd7
🔍 Latest deploy log https://app.netlify.com/projects/orbital-nebula/deploys/6ab63c5a08c9ae00076ec7a4
😎 Deploy Preview https://deploy-preview-72--orbital-nebula.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@martypitt
martypitt merged commit 77d977e into main Sep 26, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant