@crossdelta/platform-sdk 0.8.2 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,118 +1,137 @@
1
1
  <p align="center">
2
- <img src="https://unpkg.com/@crossdelta/platform-sdk/logo.png" alt="pf" width="120" />
2
+ <img src="https://unpkg.com/@crossdelta/platform-sdk/logo.png" alt="pf" width="140" />
3
3
  </p>
4
4
 
5
5
  <h1 align="center">Platform SDK</h1>
6
6
 
7
7
  <p align="center">
8
- <code>@crossdelta/platform-sdk</code>
8
+ <strong>The platform toolkit for backend + infrastructure.</strong>
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- <strong>Platform toolkit for event-driven microserviceskeeping code and infrastructure in lockstep.</strong><br />
13
- Scaffold <a href="https://turbo.build/repo">Turborepo</a> workspaces, generate services from natural language,<br />
14
- and deploy via <a href="https://www.pulumi.com">Pulumi</a> — DigitalOcean-first for speed and simplicity, providers replaceable by design.
12
+ <code>pf</code> scaffolds real-world platforms: backend services, event-driven messaging, infrastructure all wired together and kept in sync.
15
13
  </p>
16
14
 
17
15
  <p align="center">
18
- <em>Platform SDK (<code>pf</code>) is a platform opinion, not a generator.<br />
19
- It encodes architectural decisions so teams don't have to rediscover them.</em>
20
- </p>
16
+ <sub>Fontend SDK coming soon contract-based client models.</sub>
21
17
 
22
- <p align="center">
23
- <em>Includes optional AI-assisted service generation (OpenAI / Anthropic).</em>
24
18
  </p>
25
19
 
20
+ <br />
21
+
26
22
  <p align="center">
27
- <a href="https://www.npmjs.com/package/@crossdelta/platform-sdk"><img src="https://img.shields.io/npm/v/@crossdelta/platform-sdk.svg?style=flat-square" alt="npm version" /></a>
28
- <img src="https://img.shields.io/badge/bun-%E2%9A%A1-f9f1e1?style=flat-square" alt="Bun" />
29
- <img src="https://img.shields.io/badge/pulumi-ready-blueviolet?style=flat-square" alt="Pulumi" />
30
- <img src="https://img.shields.io/badge/DigitalOcean-App_Platform_|_DOKS-0080FF?style=flat-square" alt="DigitalOcean" />
23
+ <a href="https://www.npmjs.com/package/@crossdelta/platform-sdk"><img src="https://img.shields.io/npm/v/@crossdelta/platform-sdk.svg?style=for-the-badge&color=cb3837" alt="npm version" /></a>
24
+ &nbsp;
25
+ <img src="https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white" alt="TypeScript" />
26
+ &nbsp;
27
+ <img src="https://img.shields.io/badge/Bun-000000?style=for-the-badge&logo=bun&logoColor=white" alt="Bun" />
28
+ &nbsp;
29
+ <img src="https://img.shields.io/badge/License-MIT-22c55e?style=for-the-badge" alt="MIT License" />
31
30
  </p>
32
31
 
33
32
  <p align="center">
34
33
  <img src="https://img.shields.io/badge/Hono-E36002?style=flat-square&logo=hono&logoColor=white" alt="Hono" />
35
34
  <img src="https://img.shields.io/badge/NestJS-E0234E?style=flat-square&logo=nestjs&logoColor=white" alt="NestJS" />
36
35
  <img src="https://img.shields.io/badge/NATS-27AAE1?style=flat-square&logo=natsdotio&logoColor=white" alt="NATS" />
36
+ <img src="https://img.shields.io/badge/Pulumi-8A3391?style=flat-square&logo=pulumi&logoColor=white" alt="Pulumi" />
37
+ <img src="https://img.shields.io/badge/Turborepo-EF4444?style=flat-square&logo=turborepo&logoColor=white" alt="Turborepo" />
38
+ <img src="https://img.shields.io/badge/DigitalOcean-0080FF?style=flat-square&logo=digitalocean&logoColor=white" alt="DigitalOcean" />
37
39
  </p>
38
40
 
39
- ---
41
+ <br />
40
42
 
41
- ## Who is this for?
43
+ <p align="center">
44
+ <a href="#-quick-start">Quick Start</a> •
45
+ <a href="#-5-minute-tutorial">Tutorial</a> •
46
+ <a href="#-commands">Commands</a> •
47
+ <a href="#-ai-assisted-generation">AI Generation</a> •
48
+ <a href="#-deployment">Deployment</a>
49
+ </p>
42
50
 
43
- - **Teams building event-driven backends** — NATS, CloudEvents, type-safe contracts
44
- - **Startups & internal platforms** that want long-term consistency over short-term speed
45
- - **Engineers tired of infra & app drift** — ports, env vars, deployments always in sync
51
+ ---
46
52
 
47
- You can start without understanding all the pieces. The depth reveals itself as you grow.
53
+ <br />
54
+
55
+ ## 👋 Who is this for?
56
+
57
+ <table>
58
+ <tr>
59
+ <td width="60">🏗️</td>
60
+ <td><strong>Teams building full-stack platforms</strong> — services, events, apps that actually work together</td>
61
+ </tr>
62
+ <tr>
63
+ <td>📡</td>
64
+ <td><strong>Event-driven architectures</strong> — or teams ready to start using events</td>
65
+ </tr>
66
+ <tr>
67
+ <td>😤</td>
68
+ <td><strong>Engineers tired of drift</strong> — ports, env vars, and infra configs that never match</td>
69
+ </tr>
70
+ <tr>
71
+ <td>🚀</td>
72
+ <td><strong>Startups & platform teams</strong> — who want consistency without building everything from scratch</td>
73
+ </tr>
74
+ </table>
75
+
76
+ > **You can start without understanding all the pieces.**
77
+ > The depth reveals itself as you grow.
48
78
 
49
79
  ---
50
80
 
51
- ## Installation
81
+ ## 🚀 Quick Start
52
82
 
53
83
  ```bash
84
+ # With Bun
54
85
  bun add -g @crossdelta/platform-sdk
55
- # or: npm install -g @crossdelta/platform-sdk
56
- ```
57
86
 
58
- <details>
59
- <summary>Alternative: Auto-installer or run without installing</summary>
60
-
61
- **Unix/macOS:**
62
- ```bash
63
- # Auto-installer (installs CLI globally, prompts to install Bun if missing)
64
- curl -fsSL https://unpkg.com/@crossdelta/platform-sdk@latest/install.sh | bash
65
- ```
66
-
67
- **Windows:**
68
- ```powershell
69
- # Recommended: Use npm directly
87
+ # With npm
70
88
  npm install -g @crossdelta/platform-sdk
71
89
 
72
- # Or use WSL (Windows Subsystem for Linux)
73
- wsl bash -c "curl -fsSL https://unpkg.com/@crossdelta/platform-sdk@latest/install.sh | bash"
74
- ```
75
-
76
- **Run without installing:**
77
- ```bash
78
- bunx @crossdelta/platform-sdk new workspace my-platform
79
- # or: npx @crossdelta/platform-sdk new workspace my-platform
90
+ # Or auto-install (macOS/Linux/WSL)
91
+ curl -fsSL https://unpkg.com/@crossdelta/platform-sdk@latest/install.sh | bash
80
92
  ```
81
93
 
82
- </details>
83
-
84
- ---
85
-
86
- ## Quick Start
94
+ > **Windows users:** Use [WSL](https://learn.microsoft.com/en-us/windows/wsl/install) for the best experience.
87
95
 
96
+ **Then create your first platform:**
88
97
  ```bash
89
98
  pf new workspace my-platform -y && cd my-platform
90
99
  pf dev
91
100
  ```
92
101
 
93
- **What you get:**
94
- - Turborepo monorepo with Biome linting
95
- - NATS + JetStream for event-driven messaging
96
- - Pulumi infrastructure (`infra/services/*.ts`)
97
- - Auto-generated `.env.local` with service ports
98
-
99
- > **Lockstep by design:**
100
- > In `pf`, application code and infrastructure are generated from the same source of truth.
101
- > Service metadata defines ports, env vars, event wiring, and Pulumi configs —
102
- > eliminating drift between local development, CI, and production.
102
+ <br />
103
+
104
+ <table>
105
+ <tr>
106
+ <td>✅</td>
107
+ <td>Turborepo monorepo with Biome linting</td>
108
+ </tr>
109
+ <tr>
110
+ <td>✅</td>
111
+ <td>NATS + JetStream for event-driven messaging</td>
112
+ </tr>
113
+ <tr>
114
+ <td>✅</td>
115
+ <td>Pulumi infrastructure ready for deployment</td>
116
+ </tr>
117
+ <tr>
118
+ <td>✅</td>
119
+ <td>Auto-generated <code>.env.local</code> with service ports</td>
120
+ </tr>
121
+ </table>
103
122
 
104
123
  ---
105
124
 
106
- ## 5-Minute Tutorial
125
+ ## 🎯 5-Minute Tutorial
107
126
 
108
- After running Quick Start, add services and wire events:
127
+ Add two services and wire an event between them:
109
128
 
110
129
  ```bash
111
- # 1. Add two services
130
+ # 1. Create two services
112
131
  pf new hono-micro services/orders
113
132
  pf new hono-micro services/notifications
114
133
 
115
- # 2. Wire an event between them
134
+ # 2. Wire an event from orders → notifications
116
135
  pf event add orders.created --service services/notifications
117
136
 
118
137
  # 3. Restart to pick up new services
@@ -122,92 +141,194 @@ pf dev
122
141
  pf event publish orders.created
123
142
  ```
124
143
 
125
- That's it. Two services, one event contract, auto-discovered handlers, no manual wiring.
144
+ <br />
145
+
146
+ <table>
147
+ <tr>
148
+ <th align="left">What just happened</th>
149
+ </tr>
150
+ <tr>
151
+ <td>
152
+ 📦 Two services with health checks and Pulumi configs<br />
153
+ 📝 One event contract in <code>packages/contracts/</code><br />
154
+ 🔗 One handler that auto-discovers the event<br />
155
+ ✨ <strong>No manual wiring. No config drift. Everything is explicit.</strong>
156
+ </td>
157
+ </tr>
158
+ </table>
126
159
 
127
160
  ---
128
161
 
129
- ## 🧭 Commands & Options
162
+ ## 💡 What problem does pf solve?
163
+
164
+ <table>
165
+ <tr>
166
+ <th width="300">❌ The Problem</th>
167
+ <th width="300">✅ With pf</th>
168
+ </tr>
169
+ <tr>
170
+ <td>Application code lives here, infra config lives somewhere else</td>
171
+ <td>Both generated from the same source of truth</td>
172
+ </tr>
173
+ <tr>
174
+ <td>Ports, env vars, and event wiring drift over time</td>
175
+ <td>Change a service → infra stays in sync</td>
176
+ </tr>
177
+ <tr>
178
+ <td>New devs spend days setting up local environments</td>
179
+ <td>Run <code>pf dev</code> → everything starts together</td>
180
+ </tr>
181
+ <tr>
182
+ <td>Manual event subscriptions and handler registration</td>
183
+ <td>Add an event → consumers are wired automatically</td>
184
+ </tr>
185
+ </table>
130
186
 
131
- ### Service generators
187
+ ---
132
188
 
133
- **Hono** (lightweight, Bun-optimized):
134
- ```bash
135
- pf new hono-micro services/orders
136
- ```
189
+ ## 📋 Commands
137
190
 
138
- **NestJS** (full-featured, decorator-based):
139
- ```bash
140
- pf new nest-micro services/orders
141
- ```
191
+ | Command | What it does |
192
+ |:--------|:-------------|
193
+ | `pf dev` | 🚀 Start NATS + all services in watch mode |
194
+ | `pf new hono-micro <path>` | ⚡ Create a Hono service (lightweight, Bun-optimized) |
195
+ | `pf new nest-micro <path>` | 🏢 Create a NestJS service (full-featured, decorators) |
196
+ | `pf event add <type> --service <path>` | 🔗 Add contract + handler + wire stream |
197
+ | `pf event list` | 📋 List available events and consumers |
198
+ | `pf event publish <type>` | 📤 Publish mock event to NATS |
199
+ | `pf test` | 🧪 Run tests across the monorepo |
200
+ | `pf build` | 📦 Build all packages and services |
201
+ | `pf lint` | ✨ Lint and format with Biome |
202
+
203
+ > `pf` proxies all commands to Turborepo (works from any subdirectory).
204
+
205
+ ---
142
206
 
143
- Both generate the service structure, Pulumi config in `infra/services/`, and wire everything automatically.
207
+ ## 🤖 AI-Assisted Generation
144
208
 
145
- ### AI-assisted generation (optional)
209
+ > **Optional but powerful.** Configure once, then use `--ai` with any generator.
146
210
 
147
- Configure once:
148
211
  ```bash
149
212
  pf setup --ai # OpenAI or Anthropic
213
+
214
+ pf new hono-micro services/notifications --ai \
215
+ -d "Send emails when orders are created"
150
216
  ```
151
217
 
152
- Then use `--ai` with any generator:
218
+ AI generates service code, event handlers, use cases, and tests — **all following the same conventions you'd write by hand.**
219
+
220
+ ---
221
+
222
+ ## 🚢 Deployment
223
+
153
224
  ```bash
154
- pf new hono-micro services/notifications --ai -d "Send emails on order events"
225
+ pf pulumi up --stack dev
155
226
  ```
156
227
 
157
- AI generates: service code, event handlers, use cases, tests, and documentation.
158
- All generated code follows the same conventions and can be written manually.
228
+ **Pre-configured GitHub Actions included:**
159
229
 
160
- ### Daily commands
230
+ | Trigger | Action |
231
+ |:--------|:-------|
232
+ | PR to `main` | 🧪 Lint + test |
233
+ | Push to `main` | 🚀 Build, push to GHCR, deploy |
234
+ | Changes in `packages/` | 📦 Publish to npm |
161
235
 
162
- | Command | What it does |
163
- |---------|--------------|
164
- | `pf dev` | Start NATS + all services in watch mode |
165
- | `pf test` | Run tests across the monorepo |
166
- | `pf lint` | Lint and format with Biome |
167
- | `pf build` | Build all packages and services |
168
- | `pf event add <type> --service <path>` | Add contract, mock, handler + wire stream |
169
- | `pf event list` | List available events and their consumers |
170
- | `pf event publish <type>` | Publish mock event to NATS |
171
- | `pf pulumi up` | Deploy infrastructure (runs in `infra/`) |
236
+ <details>
237
+ <summary>🔐 Required secrets</summary>
238
+
239
+ <br />
240
+
241
+ | Secret | Description |
242
+ |:-------|:------------|
243
+ | `PULUMI_ACCESS_TOKEN` | [Pulumi Cloud token](https://app.pulumi.com/account/tokens) |
244
+ | `DIGITALOCEAN_TOKEN` | [DO API token](https://cloud.digitalocean.com/account/api/tokens) |
245
+ | `GHCR_TOKEN` | GitHub Container Registry PAT |
246
+
247
+ </details>
248
+
249
+ ---
172
250
 
173
- `pf` proxies to Turborepo from any subdirectory.
251
+ ## 📋 Requirements
174
252
 
175
- ### Configuration (advanced)
253
+ | Requirement | Notes |
254
+ |:------------|:------|
255
+ | **Bun** or Node.js ≥ 21 | Bun recommended for speed |
256
+ | **[Pulumi CLI](https://www.pulumi.com/docs/install/)** | For infrastructure deployment |
257
+ | **[Docker](https://www.docker.com/)** | For local NATS |
258
+
259
+ ---
260
+
261
+ ## 🔍 Under the Hood
262
+
263
+ <details>
264
+ <summary>📁 <b>Project structure</b></summary>
265
+
266
+ <br />
267
+
268
+ ```
269
+ my-platform/
270
+ ├── services/ # Your microservices
271
+ │ ├── orders/
272
+ │ └── notifications/
273
+ ├── packages/
274
+ │ └── contracts/ # Event contracts (single source of truth)
275
+ ├── infra/
276
+ │ └── services/ # Auto-generated Pulumi configs
277
+ └── .env.local # Auto-generated from infra
278
+ ```
279
+
280
+ **The key insight:** Services define their ports, env vars, and event subscriptions once. Everything else is derived.
281
+
282
+ </details>
176
283
 
177
284
  <details>
178
- <summary>Workspace configuration via <code>package.json</code></summary>
285
+ <summary>🛠️ <b>Tech stack</b></summary>
286
+
287
+ <br />
288
+
289
+ | Layer | Technology |
290
+ |:------|:-----------|
291
+ | Monorepo | [Turborepo](https://turbo.build/repo) |
292
+ | Services | [Hono](https://hono.dev) or [NestJS](https://nestjs.com) |
293
+ | Messaging | [NATS](https://nats.io) + JetStream |
294
+ | Events | [CloudEvents](https://cloudevents.io) + Zod validation |
295
+ | Infrastructure | [Pulumi](https://pulumi.com) → DigitalOcean (extensible) |
296
+ | Runtime | [Bun](https://bun.sh) |
297
+
298
+ </details>
299
+
300
+ <details>
301
+ <summary>⚙️ <b>Workspace configuration</b></summary>
302
+
303
+ <br />
179
304
 
180
305
  ```json
181
306
  {
182
307
  "pf": {
183
- "registry": "my-platform/platform",
308
+ "registry": "my-org/my-platform",
184
309
  "commands": {
185
- "pulumi": { "cwd": "infra" },
186
310
  "deploy": { "cwd": "infra", "command": "pulumi up --yes" }
187
311
  },
188
312
  "paths": {
189
313
  "services": { "path": "services", "watch": true },
190
- "apps": { "path": "apps", "watch": true },
191
- "packages": { "path": "packages", "watch": true },
192
314
  "contracts": { "path": "packages/contracts" }
193
315
  }
194
316
  }
195
317
  }
196
318
  ```
197
319
 
198
- - `commands`: Custom shortcuts with working directory overrides
199
- - `paths.<type>.watch`: Enable file watching in dev mode
200
- - `paths.<type>.ignorePatterns`: Glob patterns to exclude
201
-
202
320
  </details>
203
321
 
204
322
  <details>
205
- <summary>Infrastructure configuration via <code>infra/services/*.ts</code></summary>
323
+ <summary>🏗️ <b>Service infrastructure config</b></summary>
206
324
 
207
- ```ts
325
+ <br />
326
+
327
+ ```typescript
328
+ // infra/services/orders.ts
208
329
  import { ports, type K8sServiceConfig } from '@crossdelta/infrastructure'
209
330
 
210
- export const config: K8sServiceConfig = {
331
+ const config: K8sServiceConfig = {
211
332
  name: 'orders',
212
333
  ports: ports().http(4001).build(),
213
334
  replicas: 1,
@@ -217,102 +338,21 @@ export const config: K8sServiceConfig = {
217
338
  limits: { cpu: '150m', memory: '128Mi' },
218
339
  },
219
340
  }
341
+
342
+ export default config
220
343
  ```
221
344
 
222
345
  See [@crossdelta/infrastructure](https://www.npmjs.com/package/@crossdelta/infrastructure) for full options.
223
346
 
224
347
  </details>
225
348
 
226
- ---
227
-
228
- ## 🎯 Why This Exists
229
-
230
- `pf` solves platform engineering problems:
231
-
232
- - **Infrastructure drift** — Infra configs diverge from code in separate repos
233
- - **Manual wiring** — Ports, env vars, service discovery configured by hand
234
- - **Slow onboarding** — New devs spend days setting up local environments
235
-
236
- **Solution:** Services auto-generate `infra/services/*.ts`, ports/env derived automatically, event handlers type-safe and auto-discovered.
237
-
238
- **In short: docker-compose starts services — `pf` prevents systems from drifting apart over time.**
239
-
240
- ---
241
-
242
- ## 🧩 What pf Is / Is Not
243
-
244
- **✅ pf is:**
245
- - Opinionated platform toolkit for event-driven microservices
246
- - Turborepo scaffolder with Pulumi IaC and NATS messaging built-in
247
- - AI-assisted code generator from natural language descriptions
248
- - Unified dev workflow — one command to run everything
249
- - DigitalOcean-first for speed and simplicity — providers replaceable by design
250
-
251
- **❌ pf is not:**
252
- - Generic microservice generator — makes architectural choices for you
253
- - Multi-cloud out of the box — DigitalOcean first, extensible to other providers
254
- - Runtime manager — scaffolds code, you deploy with Pulumi
255
-
256
- **Note:** `pf` runs nothing implicitly. No hidden daemons, no automatic deployments. You control when code runs and infrastructure deploys.
257
-
258
- ---
259
-
260
- ## 🏗️ Architecture
261
-
262
- ```
263
- my-platform/
264
- ├── services/ # Microservices
265
- │ ├── nats/ # NATS message broker (auto-scaffolded)
266
- │ └── <service>/
267
- │ └── src/
268
- │ ├── events/ # Event handlers (*.event.ts)
269
- │ ├── use-cases/ # Business logic (*.use-case.ts)
270
- │ ├── types/ # Zod schemas
271
- │ └── index.ts
272
- ├── packages/
273
- │ └── contracts/ # Event contracts (Schema Registry)
274
- ├── infra/ # Pulumi Infrastructure-as-Code
275
- │ └── services/ # Per-service K8s configs
276
- └── .env.local # Auto-generated from infra
277
- ```
278
-
279
- ### Conventions
280
-
281
- | Location | Purpose |
282
- |----------|---------|
283
- | `services/*/src/events/*.event.ts` | Event handlers (auto-discovered) |
284
- | `services/*/src/use-cases/*.use-case.ts` | Business logic (pure functions) |
285
- | `packages/contracts/src/events/*.ts` | Event contracts (single source of truth) |
286
- | `infra/services/*.ts` | Pulumi configs per service |
287
-
288
- > **Schema Registry pattern:**
289
- > All event contracts live in `packages/contracts` as the single source of truth.
290
- > Services import contracts instead of redefining schemas, ensuring
291
- > type safety, compatibility, and explicit ownership across service boundaries.
292
-
293
- ### Event-Driven Pattern
294
-
295
- **Add events with one command:**
296
- ```bash
297
- # Creates contract, mock, handler, and wires the stream automatically
298
- pf event add orders.created --service services/notifications
299
- ```
300
-
301
- This generates:
302
- - `packages/contracts/src/events/orders-created.ts` (contract)
303
- - `packages/contracts/src/events/orders-created.mock.json` (test data)
304
- - `services/notifications/src/events/orders-created.event.ts` (handler)
305
- - Adds stream to service `index.ts` if needed
349
+ <details>
350
+ <summary>📡 <b>Event-driven architecture</b></summary>
306
351
 
307
- **Test events locally:**
308
- ```bash
309
- pf event list # Show available events
310
- pf event publish orders.created # Publish mock event to NATS
311
- ```
352
+ <br />
312
353
 
313
- **Manual pattern (if you prefer):**
354
+ **Contracts** live in `packages/contracts/` as the single source of truth:
314
355
 
315
- **1. Define contract:**
316
356
  ```typescript
317
357
  // packages/contracts/src/events/orders-created.ts
318
358
  import { createContract } from '@crossdelta/cloudevents'
@@ -324,25 +364,27 @@ export const OrdersCreatedContract = createContract({
324
364
  })
325
365
  ```
326
366
 
327
- **2. Publish (Service A):**
328
- ```typescript
329
- // services/orders/src/use-cases/create-order.use-case.ts
330
- await publish(OrdersCreatedContract, { orderId: '123', total: 99.99 })
331
- ```
367
+ **Handlers** import contracts and delegate to use cases:
332
368
 
333
- **3. Handle (Service B, auto-discovered):**
334
369
  ```typescript
335
370
  // services/notifications/src/events/orders-created.event.ts
371
+ import { handleEvent } from '@crossdelta/cloudevents'
372
+ import { OrdersCreatedContract } from '@my-org/contracts'
373
+ import { sendOrderNotification } from '../use-cases/send-notification.use-case'
374
+
336
375
  export default handleEvent(OrdersCreatedContract, async (data) => {
337
376
  await sendOrderNotification(data)
338
377
  })
339
378
  ```
340
379
 
341
- No manual subscriptions. Convention over configuration.
380
+ Handlers are auto-discovered. No manual subscriptions.
342
381
 
343
- ---
382
+ </details>
383
+
384
+ <details>
385
+ <summary>⚡ <b>NATS message broker</b></summary>
344
386
 
345
- ## ⚡ NATS Message Broker
387
+ <br />
346
388
 
347
389
  Every workspace includes pre-configured NATS with JetStream:
348
390
 
@@ -350,46 +392,39 @@ Every workspace includes pre-configured NATS with JetStream:
350
392
  - Ports: `4222` (client), `8222` (monitoring)
351
393
  - Health check: `curl http://localhost:8222/healthz`
352
394
 
353
- See `services/nats/README.md` for details.
395
+ </details>
354
396
 
355
397
  ---
356
398
 
357
- ## Deployment
358
-
359
- ```bash
360
- pulumi login && pulumi up --stack dev
361
- ```
399
+ ## 🧭 Philosophy
362
400
 
363
- ### GitHub Actions (pre-configured)
401
+ <table>
402
+ <tr>
403
+ <td width="50%">
364
404
 
365
- | Workflow | Trigger | Purpose |
366
- |----------|---------|---------|
367
- | `lint-and-tests.yml` | PR to `main` | Lint + test |
368
- | `build-and-deploy.yml` | Push to `main` | Build, push to GHCR, deploy |
369
- | `publish-packages.yml` | Changes in `packages/` | Publish to npm |
405
+ ### What pf is
370
406
 
371
- <details>
372
- <summary>Required secrets</summary>
407
+ - Opinionated full-stack platform toolkit
408
+ - Unified dev workflow — one command to run everything
409
+ - Infrastructure that stays in sync with your code
373
410
 
374
- | Secret | Description |
375
- |--------|-------------|
376
- | `PULUMI_ACCESS_TOKEN` | [Pulumi Cloud token](https://app.pulumi.com/account/tokens) |
377
- | `DIGITALOCEAN_TOKEN` | [DO API token](https://cloud.digitalocean.com/account/api/tokens) |
378
- | `GHCR_TOKEN` | GitHub Container Registry PAT |
379
- | `NPM_TOKEN` | [npm access token](https://www.npmjs.com/settings/~/tokens) (only for `publish-packages.yml`) |
411
+ </td>
412
+ <td width="50%">
380
413
 
381
- </details>
414
+ ### ❌ What pf is not
382
415
 
383
- ---
416
+ - Generic scaffolder — it makes choices for you
417
+ - Multi-cloud out of the box — DigitalOcean first, extensible later
418
+ - Magic — no hidden daemons, you control when things run
384
419
 
385
- ## 📚 Requirements
420
+ </td>
421
+ </tr>
422
+ </table>
386
423
 
387
- - **Bun** (recommended) or Node.js 21
388
- - **[Pulumi CLI](https://www.pulumi.com/docs/install/)** for deployment
389
- - **[Docker](https://www.docker.com/)** for local NATS
424
+ > **`pf` makes architectural decisions so your team doesn't have to — without hiding how things work.**
390
425
 
391
426
  ---
392
427
 
393
- ## 📄 License
394
-
395
- MIT © Crossdelta
428
+ <p align="center">
429
+ <strong>MIT © crossdelta</strong>
430
+ </p>