From 643d7591d26180c62c26aba5c9029e38bf4f8524 Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Wed, 1 Jul 2026 15:40:33 -0700 Subject: [PATCH] Remove discussion.md to streamline documentation and focus on core concepts for castle's design. --- docs/working/discussion.md | 664 ------------------------------------- 1 file changed, 664 deletions(-) delete mode 100644 docs/working/discussion.md diff --git a/docs/working/discussion.md b/docs/working/discussion.md deleted file mode 100644 index f9d99ed..0000000 --- a/docs/working/discussion.md +++ /dev/null @@ -1,664 +0,0 @@ -Yes — that changes the design a lot, in a good way. - -If **castle is not a general platform**, but a **curated machine for you + an AI assistant**, then the ontology should be optimized for: - -* few concepts -* strong defaults -* predictable placement -* limited extension paths -* easy generation from natural language - -That means castle should **not** try to model all possible machine semantics. Ubuntu already does that. Castle should define a **small opinionated overlay** on top of Ubuntu. - -So I’d stop trying to find the perfect universal ontology and instead design a **usefully incomplete one**. - -## The design principle - -Castle should answer: - -> What are the few things I commonly want the machine to have or do? - -From your examples, those are roughly: - -* a **tool** -* a **site** -* a **service** -* a **worker/daemon** -* a **job** -* a **store/broker** -* maybe a **library/project** - -That suggests the core user-facing abstraction should not be “artifact” or “namespace” or even “runtime.” - -It should be something more like: - -## Castle’s main abstraction: `unit` - -A **unit** is a thing the castle machine knows how to host. - -That thing may be: - -* a Python tool -* a static site -* a web service -* a daemon -* a scheduled job -* a database -* a broker - -Then beneath that, castle can have a smaller set of internal dimensions. - ---- - -# A much simpler castle model - -I think the practical model is: - -```text -unit -kind -stack -uses -``` - -Where: - -## `unit` - -The named thing on the machine. - -Examples: - -* `reddit-tool` -* `docs-site` -* `api` -* `transform-worker` -* `morning-search` -* `postgres` -* `mqtt` - -## `kind` - -The machine role. - -Examples: - -* `tool` -* `site` -* `service` -* `worker` -* `job` -* `store` -* `broker` - -## `stack` - -How it is built/run. - -Examples: - -* `python` -* `rust` -* `react-static` -* `fastapi` -* `shell` - -This is where language/build/runtime conventions collapse into one curated choice. - -## `uses` - -What castle subsystems or other units it depends on. - -Examples: - -* `postgres` -* `neo4j` -* `mqtt` -* `caddy` -* `reddit` -* `web` - -This is much closer to how you actually want to talk to the AI. - ---- - -# Why this is better - -You don’t want to say: - -> create a deployment of kind service using runtime python with artifact class program and lifecycle systemd - -You want to say: - -> add a Python service that does X and uses Postgres - -So castle should be shaped around **intentional unit kinds**, not abstract machine theory. - -The machine theory should stay underneath as implementation. - ---- - -# What castle can standardize - -Because castle is curated, you can hardcode a lot: - -## Always true on castle - -* Ubuntu -* systemd -* Caddy -* standard directory layout -* standard logging -* standard service supervision -* standard way to expose commands on PATH -* standard way to run Python via `uv` -* standard way to build JS via `pnpm` -* standard way to define dependencies between units - -That means users and AI do **not** need to specify those every time. - -This is the key simplification move. - ---- - -# Recommended fixed subsystems - -I’d make these built-in castle subsystems: - -* **python** via `uv` -* **rust** via `cargo` -* **node/react** via `pnpm` -* **java** via one standard choice -* **caddy** -* **systemd** -* **postgres** -* **mqtt** -* maybe **neo4j** -* maybe **web-search ingestion** as a castle-native capability - -Then the schema does not need to model arbitrary runtimes. It only needs to reference these known capabilities. - ---- - -# Strong defaults for placement - -You said castle can always use well-known spots. Good. Do that aggressively. - -For example: - -```text -/castle/units//src -/castle/units//build -/castle/units//env -/castle/units//state -/castle/units//config -/castle/units//logs -``` - -And for exposure: - -```text -/castle/bin/ -/castle/sites/ -/castle/data/ -``` - -Then castle itself can generate: - -* symlinks into `/usr/local/bin` -* systemd units -* Caddy config -* env files -* state dirs - -So the schema does not need to talk much about placement, because placement is mostly implied. - ---- - -# The actual user-facing kinds - -I’d recommend just these: - -## 1. `tool` - -A command you can run from anywhere. - -Examples: - -* Python CLI -* Rust CLI -* shell helper - -Defaults: - -* exposed on PATH -* no long-running process -* build/install conventions by stack - -Example: - -```yaml -units: - summarize-reddit: - kind: tool - stack: python -``` - ---- - -## 2. `site` - -A human-facing HTTP site served by Caddy. - -Examples: - -* React static site -* docs site -* maybe proxied app frontend later - -Defaults: - -* served by Caddy -* standard root dir -* standard local hostname or port - -Example: - -```yaml -units: - castle-web: - kind: site - stack: react-static - port: 8080 -``` - ---- - -## 3. `service` - -A long-running HTTP or TCP process supervised by systemd. - -Examples: - -* FastAPI app -* Rust API -* Java backend - -Defaults: - -* systemd-managed -* logs to journal -* optional Caddy exposure if HTTP -* standard environment/config paths - -Example: - -```yaml -units: - reddit-api: - kind: service - stack: fastapi - port: 9090 - uses: [postgres, neo4j, reddit] -``` - ---- - -## 4. `worker` - -A long-running non-HTTP daemon, often connected to broker/store inputs. - -Examples: - -* MQTT consumer -* pubsub transformer -* sync loop -* queue processor - -Defaults: - -* systemd-managed -* usually not publicly exposed -* can subscribe to broker/topic or poll/store - -Example: - -```yaml -units: - topic-transformer: - kind: worker - stack: python - uses: [mqtt] - subscribe: channel-b - publish: channel-y -``` - -This kind seems especially important for your goals. - ---- - -## 5. `job` - -A scheduled or one-shot task. - -Examples: - -* morning search -* report generation -* backup -* fetch and write JSON - -Defaults: - -* systemd timer -* writes to known output locations -* can use web-search capability - -Example: - -```yaml -units: - morning-z-search: - kind: job - stack: python - schedule: daily@08:00 - uses: [web] - outputs: - - /castle/shared/search/z/ -``` - ---- - -## 6. `store` - -A built-in stateful service. - -Examples: - -* Postgres -* Neo4j - -Defaults: - -* castle manages lifecycle and placement -* other units reference by name - -Example: - -```yaml -units: - postgres: - kind: store - engine: postgres - - neo4j: - kind: store - engine: neo4j -``` - -You may even decide these are so built-in they don’t need to be declared unless customized. - ---- - -## 7. `broker` - -A built-in messaging service. - -Examples: - -* MQTT - -Example: - -```yaml -units: - mqtt: - kind: broker - engine: mqtt -``` - -Again, maybe built-in by default. - ---- - -# The schema can now be tiny - -Instead of a universal schema, use a compact one with per-kind defaults. - -Example: - -```yaml -units: - reddit-tool: - kind: tool - stack: python - description: CLI for querying reddit summaries - - castle-web: - kind: site - stack: react-static - port: 8080 - - reddit-api: - kind: service - stack: fastapi - port: 9090 - uses: [postgres, neo4j, reddit] - - topic-transformer: - kind: worker - stack: python - uses: [mqtt] - subscribe: channel-b - publish: channel-y - - morning-z-search: - kind: job - stack: python - schedule: "daily@08:00" - uses: [web] - output_dir: /castle/shared/search/z -``` - -That is probably closer to the right level. - ---- - -# What `stack` should mean now - -Since castle is curated, `stack` can absorb a lot: - -Instead of: - -* build system -* runtime -* conventions -* entrypoint rules - -just use a known stack name. - -Examples: - -* `python` -* `fastapi` -* `rust` -* `react-static` -* `java-service` -* `shell` - -Each stack implies: - -* where source goes -* how to build -* how to run -* what files are expected -* how dependencies are installed - -This is much simpler than separately modeling build/runtime/deployment for every case. - -So for castle: - -> **stack = curated implementation pattern** - -That’s probably the right definition. - ---- - -# What `uses` should mean - -This is another very valuable simplification. - -Instead of asking the user to define bindings and interfaces, let them say what the unit uses. - -Examples: - -* `postgres` -* `neo4j` -* `mqtt` -* `caddy` -* `web` -* `reddit` -* another unit name - -Then castle knows how to wire it. - -Example: - -```yaml -uses: [postgres, neo4j, reddit] -``` - -could imply: - -* env vars for local connection strings -* service ordering in systemd -* generated client config -* AI awareness that those capabilities are available - -This is much more useful than formal dependency graphs. - ---- - -# Under the hood - -Internally, castle can still map to: - -* artifacts -* runtimes -* systemd -* Caddy -* mount namespaces -* env files -* directories - -But that should be hidden. - -The AI assistant should primarily think in terms of: - -* **What kind of unit is this?** -* **What stack should it use?** -* **What does it use?** -* **What should it be named?** - -That’s enough to generate the machine config. - ---- - -# So the real castle ontology may be - -## User-facing - -```text -unit -kind -stack -uses -``` - -## Machine-facing - -```text -source -artifact -runtime -deployment -placement -``` - -This split is important. - -You were trying to find one ontology for both humans and machines. You probably want two: - -* a **simple command ontology** for you + AI -* a **lower-level implementation ontology** for castle internals - -That resolves a lot of the tension. - ---- - -# Example natural language mapping - -“Add a python tool that does X” - -becomes: - -```yaml -name: x-tool -kind: tool -stack: python -``` - -“Make a web service that does Y” - -becomes: - -```yaml -name: y-service -kind: service -stack: fastapi -``` - -“Make a daemon that watches pubsub channel B and transforms the data and puts it on Y” - -becomes: - -```yaml -name: b-to-y -kind: worker -stack: python -uses: [mqtt] -subscribe: B -publish: Y -``` - -“Every morning, do a web search for Z and put the results in PATH as json files” - -becomes: - -```yaml -name: z-search -kind: job -stack: python -uses: [web] -schedule: daily@08:00 -output_dir: /castle/shared/search/z -format: json -``` - -This is very manageable. - ---- - -# Recommendation - -I would make castle intentionally opinionated around: - -* **7 unit kinds max** -* **5–8 stacks max** -* **a handful of built-in capabilities in `uses`** -* **fixed placement conventions** -* **automatic generation of systemd/Caddy/config** - -That seems like the right balance of simplicity and extensibility for what you want. - -The next useful step is to draft the **minimal v1 castle schema** with only those user-facing fields and strong defaults.