carlos / platform Public

rootfs apps: rev 4, carlos console shorthand, stateless replicas before the Kubernetes move

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 8bca6501f76cf100820a7b6137def42066169fd8 parent 7e92df7
1 file changed, +40 −15
  • docs/superpowers/specs/2026-10-24-rootfs-apps-design.md +40 −15

CI cancelled — superseded by a newer push — run details

diff --git a/docs/superpowers/specs/2026-10-24-rootfs-apps-design.md b/docs/superpowers/specs/2026-10-24-rootfs-apps-design.md
index 9998bbb30..4c0e843e9 100644
--- a/docs/superpowers/specs/2026-10-24-rootfs-apps-design.md
+++ b/docs/superpowers/specs/2026-10-24-rootfs-apps-design.md
@@ -1,12 +1,14 @@
# Rootfs apps: run any Linux app on your own boxes, isolated like a CARLOS instance
**Date:** 2026-10-24
-**Revision:** 3. Draft from a brainstorming session with Paul, 2026-10-24.
+**Revision:** 4. Draft from a brainstorming session with Paul, 2026-10-24.
Rev 2 answers Astra's builder check (`CODEX-FINDINGS-ROOTFS-APPS-R1.md`,
six questions): §5.0 is new, §5.6 and §5.7 are narrowed, §5.2 settles
deploy overlap. Marked **(B1-n)**. Rev 3 adds the `release` process
(§5.2.1, Paul: "Perfect"), makes `carlos run` part of v1 (§5.5) and adds
-interactive sessions (§5.10).
+interactive sessions (§5.10). Rev 4: `carlos console` as a declared
+shorthand (§5.10), and Q1 answered: stateless replicas land before
+step 3 (§6, §13).
**Discussion:** amadan carlos/platform #366.
**Base:** origin/main 64a002c8.
@@ -251,8 +253,8 @@ The manifest names processes:
}
```
-- Exactly one `web`, required. At most one `release` (§5.2.1). Zero or
- more others, which are workers, names matching a
+- Exactly one `web`, required. At most one `release` (§5.2.1) and at
+ most one `console` (§5.10). Zero or more others, which are workers, names matching a
short identifier pattern. Commands are argv arrays, absolute or
resolved against the image's `PATH`. Optional `env` (plain values,
no secrets) and `working_dir` per process.
@@ -503,9 +505,22 @@ interactive session needs a live, two-way stream with a terminal.
- **Command.** `carlos run --interactive` (`-it`), e.g.
`carlos run -it --app shop --instance shop.example.com -- bin/rails console`.
- My call over a new `carlos console` verb: "the console" already names
- the control plane in the docs and CLI, and `-it` is what Docker and
- kubectl users expect.
+ `-it` is what Docker and kubectl users expect.
+- **`carlos console` is shorthand** (Paul, 2026-10-24) for
+ `carlos run -it` of the app's declared `console` process:
+ ```json
+ "console": {"command": ["bin/rails", "console"]}
+ ```
+ The platform never inspects an image to guess the framework (R6).
+ Detection happens on the developer's machine: `carlos ship` fills in
+ `console` when the source looks like a known framework and the
+ manifest does not declare one, and says what it filled in. Rails
+ (`bin/rails` and `config/application.rb`): `bin/rails console`.
+ Laravel (`artisan`): `php artisan tinker`. Django (`manage.py`):
+ `python manage.py shell`. An explicit `console` always wins. An app
+ with no `console` gets a refusal from `carlos console` that names
+ `carlos run -it` and the manifest key. `console` is never started by
+ the platform on its own; it exists only to be run interactively.
- **Transport.** CLI to console over a WebSocket; console to box over the
box's existing outbound tunnel (fleet boxes have no inbound path, and
need none); on the box, the agent asks the control service for a
@@ -520,7 +535,7 @@ interactive session needs a live, two-way stream with a terminal.
`carlos run`, an idle timeout, and the run design's maximum duration.
- Works for binary apps too, if they ship a shell or REPL; nothing here
is rootfs-only except the image the session runs from.
-- Not required for step 1 of §6. Required before step 3: a team leaving
+- Not required for step 1 of §6. Required before step 4: a team leaving
Kubernetes uses `kubectl exec -it ... rails console` and will miss it.
## 6. Order of work
@@ -531,10 +546,13 @@ interactive session needs a live, two-way stream with a terminal.
§5.8. Neutral names in everything (`shop`, `example.com`).
2. **A tenant's own single-tenant deployment goes nested.** Separate
work, outside this design. It is what makes isolation real there.
-3. **The Rails app off Kubernetes** onto that deployment: MySQL and
+3. **Stateless replicas** (separate design, §12). Paul, 2026-10-24: they
+ land before the Kubernetes move.
+4. **The Rails app off Kubernetes** onto that deployment: MySQL and
Redis in the same region through §5.9's egress allow, Sidekiq as a
- declared worker, existing uploads through env keys. Whether it also
- needs stateless replicas first is §13 Q1.
+ declared worker, existing uploads through env keys, several copies on
+ several boxes, `release` run once per release (§5.2.1), and
+ interactive sessions (§5.10).
### 6.1 What the sample app must show
@@ -628,14 +646,18 @@ resource IDs. Managed databases are the customer's choice of endpoint.
- Seeds for rootfs are desirable, not required for v1; `carlos run` is
required.
- `release` timeout 10 minutes by default (§5.2.1).
-- Interactive sessions as `carlos run -it`, not `carlos console`; off by
- default per app; needed before step 3, not step 1 (§5.10).
+- Interactive sessions as `carlos run -it`, with `carlos console` as the
+ shorthand for a declared `console` process that `carlos ship` fills in
+ locally for Rails, Laravel and Django; off by default per app; needed
+ before step 4, not step 1 (§5.10).
- The egress allow is in this design because step 3 cannot happen
without it, but it is not needed for step 1 and can land after it.
## 12. Follow-ups (separate designs)
-- **Stateless replicas** (wanted, Paul 2026-10-24): N copies of an app
+- **Stateless replicas** (wanted, and a prerequisite for the Kubernetes
+ move, Paul 2026-10-24). It must also define `release`'s run-once
+ scope (§5.2.1) and how a "no local database" app is declared (§5.6): N copies of an app
with no local state, on several boxes, behind the edge or a load
balancer, with no lease and no litestream. Two kinds of first user:
rootfs apps that declare no local database, and existing binary apps
@@ -657,4 +679,7 @@ settled above as my calls. B1-6 is Q1.
sense", and some apps already keep all their state in S3 with
compare-and-swap. So the stateless-replicas design is wanted, for
those apps as much as for rootfs ones. Its order relative to step 3 is
- still open.
+ still open. **Answered (Paul, 2026-10-24): yes, stateless replicas land
+ before the Kubernetes migration.** §6 now has it as step 3.
+
+No open questions remain.