<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[TDK CLI]]></title><description><![CDATA[Official guides for TDK CLI. Go from an empty folder to a running multi-service stack with hot reload using one service.json and tdk up. No Kubernetes for local development. Agentic Infrastructure.
]]></description><link>https://tdk-cli.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Thu, 29 Oct 2026 03:01:41 GMT</lastBuildDate><atom:link href="https://tdk-cli.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[On Windows, start the stack in Ubuntu]]></title><description><![CDATA[Native Windows can inspect. It cannot start the stack. The start path is Ubuntu on WSL2, in the Ubuntu shell, not in PowerShell and not in cmd. Docker has…]]></description><link>https://tdk-cli.hashnode.dev/on-windows-start-the-stack-in-ubuntu</link><guid isPermaLink="true">https://tdk-cli.hashnode.dev/on-windows-start-the-stack-in-ubuntu</guid><dc:creator><![CDATA[odykyi]]></dc:creator><pubDate>Thu, 22 Oct 2026 20:23:40 GMT</pubDate><content:encoded><![CDATA[<hr />
<p>Native Windows can inspect. It cannot start the stack. The start path is Ubuntu on WSL2, in the Ubuntu shell, not in PowerShell and not in <code>cmd</code>.</p>
<p>Docker has to be Linux containers, with WSL2 integration on. If <code>flisk doctor</code> says the daemon is using the Windows engine, that is the fix it already printed. Switch the engine. Do not keep typing <code>flisk up</code> at the same prompt.</p>
<h2>The path in the docs</h2>
<p>Run this in Ubuntu. The first command copies the bundled example into your home directory. The second configures that copy.</p>
<pre><code class="language-bash">flisk doctor
flisk project example --path "$HOME/tdk-example"
cd "$HOME/tdk-example"
flisk project --yes
sed -i 's/^INFISICAL_ENABLED=.*/INFISICAL_ENABLED=false/' .env
flisk config verify
flisk doctor
flisk up shop
</code></pre>
<p>Leave <code>flisk up shop</code> running. Use a second Ubuntu terminal for curl. Set <code>HTTP_PORT</code> to the port that <code>flisk up</code> printed. That is 80 when port 80 is free, and 8080 on WSL2 when it is not. Do not assume 80 because a Mac screenshot showed 80.</p>
<p>The repo has a smoke test that does the same shape: copy the example, doctor, verify, boot, hit the routed write, watch the worker, tear the stack down. If your manual run cannot create an order and see the worker mark it, you do not have the example running. You have a container that happened to start.</p>
<h2>What people skip</h2>
<p><code>sed</code> turns Infisical off in that example's <code>.env</code>. Skip it and the boot is waiting on a secrets tool you did not mean to use.</p>
<p><code>flisk config verify</code> before the second doctor is there because a hand-edited generated file should fail before Tilt does. If verify fails, regenerate. Do not "fix" the Tiltfile in the Ubuntu home directory and call that a Windows bug.</p>
<p>Files written from Windows onto the Linux filesystem, or the other way around, are a WSL problem, not a Flisk feature. Keep the repo in the Linux home directory if the bind mounts look empty.</p>
<p><a href="https://github.com/flisk-sh/flisk/blob/main/docs/wsl2.md">WSL2 notes</a></p>
<p><a href="https://flisk.sh">flisk.sh</a></p>
]]></content:encoded></item><item><title><![CDATA[A Premium key is not a support contract]]></title><description><![CDATA[flisk up does not need a key. Core is MIT. Most teams should stay there. Premium is optional, at $19 per developer per month, and it unlocks extras. It…]]></description><link>https://tdk-cli.hashnode.dev/a-premium-key-is-not-a-support-contract</link><guid isPermaLink="true">https://tdk-cli.hashnode.dev/a-premium-key-is-not-a-support-contract</guid><dc:creator><![CDATA[odykyi]]></dc:creator><pubDate>Thu, 22 Oct 2026 20:20:11 GMT</pubDate><content:encoded><![CDATA[<hr />
<p><code>flisk up</code> does not need a key. Core is MIT. Most teams should stay there. Premium is optional, at $19 per developer per month, and it unlocks extras. It does not buy an SLA, a weekend page, or a promise that someone will join your incident.</p>
<p>The repo is explicit about what it does not publish: the price lives on the site, the licence terms for the premium code are not in the tree, and a premium key is a feature key. Read that again before you put the key in a runbook titled "support".</p>
<h2>What the key is for</h2>
<p>The extras called out in the project docs are a local Verdaccio registry, a DDD scaffold, and idle stop. They are gated. The core path, including <code>flisk up</code>, is not.</p>
<p>Set the key in the environment the CLI already looks at:</p>
<pre><code class="language-bash">export TDK_LICENSE_KEY="the-key-you-were-sent"
</code></pre>
<p>The variable still says <code>TDK_</code> because the on-disk names were not all renamed. That is the same CLI. See the post about <code>flisk</code> versus <code>tdk</code> if that bothers you. Do not invent <code>FLISK_LICENSE_KEY</code> and then wonder why the extra stayed locked.</p>
<p>A key is capped. The site says up to 100 project IDs on one key. A key posted in a public chat is not a team plan. It is a key you can no longer revoke per person.</p>
<h2>What you do not get</h2>
<p>You do not get production hosting. You do not get Helm values. You do not get a measured onboarding number. The speed figures on the site are lab runs, including a 100-service health fixture that is not an ERP. The savings calculator is arithmetic on inputs you type.</p>
<p>You also do not get a second support tier because you paid. If <code>flisk doctor</code> fails, the fix is the <code>ℹ Fix:</code> line. A key does not change that line.</p>
<p>If you want a key, use the request on <a href="https://flisk.sh">flisk.sh</a>. If you do not want the extras, do not request one. The free CLI is the product. The $19 is a feature flag with a price, not a reason to migrate a monorepo.</p>
<p><a href="https://github.com/flisk-sh/flisk">github.com/flisk-sh/flisk</a></p>
]]></content:encoded></item><item><title><![CDATA[Omit --language. The backend is Bun.]]></title><description><![CDATA[flisk resource --type backend scaffolds Bun and Hono. That is the default on purpose. Omit --language and the output stays byte-identical to the historical…]]></description><link>https://tdk-cli.hashnode.dev/omit-language-the-backend-is-bun</link><guid isPermaLink="true">https://tdk-cli.hashnode.dev/omit-language-the-backend-is-bun</guid><dc:creator><![CDATA[odykyi]]></dc:creator><pubDate>Thu, 22 Oct 2026 20:18:55 GMT</pubDate><content:encoded><![CDATA[<h2>tags: flisk, bun, node, backend</h2>
<p><code>flisk resource --type backend</code> scaffolds Bun and Hono. That is the default on purpose. Omit <code>--language</code> and the output stays byte-identical to the historical scaffold. Interactive create does not ask you to pick a language.</p>
<p>Python, Go, Rust, and Node are opt-in. You name them, or you do not get them.</p>
<pre><code class="language-bash">flisk resource api --type backend --stack shop --yes
flisk resource api --type backend --language go --stack shop
flisk resource --type backend --frameworks
</code></pre>
<p>The first command is the default. The second is an explicit provider. The third lists registered backend frameworks: id, display name, the language they scaffold with, and the command that creates them. An unknown id fails before any file is written. <code>Python</code> and <code>python</code> match. A legacy <code>service.json</code> with no <code>language</code> field stays valid and is not rewritten.</p>
<h2>What Go actually writes</h2>
<p><code>--language go</code> writes <code>go.mod</code>, <code>main.go</code>, and <code>main_test.go</code>. The server is the standard library, <code>GET /health</code>, reads <code>PORT</code>, and listens on every interface. The image is a <code>golang:1.23</code> build stage plus a production stage, because Tilt builds <code>--target production</code>. A test stage is there so CI can run the language's tests in the image.</p>
<p>The id is stored as <code>framework</code> in <code>service.json</code>. Omitting the flag writes no <code>framework</code> field.</p>
<p>Live reload is also opt-in. Add it, then run <code>flisk up</code> again:</p>
<pre><code class="language-json">{ "dev": { "liveReload": true } }
</code></pre>
<h2>What not to do in a pull request</h2>
<p>One language per pull request. Copy the Python provider and its tests. Register it. Add the Dockerfile template. Do not edit <code>engine/schemas/service-schema.json</code> to add the id. <code>language</code> there is an open string. The CLI registry is what rejects an unknown id.</p>
<p>Do not add that language's dependencies to the CLI package. Do not "improve" the default by making interactive create prompt for a language. Bun stays the default so old output does not move under you.</p>
<p><code>flisk config regenerate</code> rebuilds project-level config. It does not recreate resource source. If you wanted a Go service and you already generated Bun, make a new resource with <code>--language go</code>. Do not hand-convert <code>main.go</code> into the Bun directory and expect verify to bless it.</p>
<p><a href="https://github.com/flisk-sh/flisk/blob/main/docs/backend-language-providers.md">Backend language providers</a></p>
<p><a href="https://flisk.sh">flisk.sh</a></p>
]]></content:encoded></item><item><title><![CDATA[Just read description]]></title><description><![CDATA[I got tired of local microservices turning into a pile of Dockerfiles, Compose files, and nginx configs that nobody wants to maintain. Agents are worse at…]]></description><link>https://tdk-cli.hashnode.dev/just-read-description</link><guid isPermaLink="true">https://tdk-cli.hashnode.dev/just-read-description</guid><dc:creator><![CDATA[odykyi]]></dc:creator><pubDate>Tue, 20 Oct 2026 23:36:36 GMT</pubDate><content:encoded><![CDATA[<p>I got tired of local microservices turning into a pile of Dockerfiles, Compose files, and nginx configs that nobody wants to maintain. Agents are worse at it than people. They rewrite a Dockerfile, break the Tiltfile, and burn a bunch of tokens fixing plumbing instead of the app.
So I built TDK CLI. You keep one service.json next to each service. tdk up generates the local runtime and starts it. Docker runs the containers. Tilt live-reloads them. No local Kubernetes.
you keep                         tdk up writes                  what runs</p>
<hr />
<p>services/orders-api/             .autogenerated/                Docker
  service.json  -- tdk up --&gt;      Dockerfile                     |
  src/                               Tiltfile                      v
                                     Traefik routes            Tilt watches
                                                                  |
                                                                  v
                                                          api.shop.localhost
A small shop stack looks like this:
                         tdk up shop
                              |
          +-------------------+-------------------+
          |                   |                   |
     orders-api          storefront            postgres
          |                   |                   |
          +-------------------+-------------------+
                              |
                           Traefik
                              |
                     *.shop.localhost
The shortest loop:
mkdir shop &amp;&amp; cd shop
tdk project --yes
tdk resource orders-api --type backend --stack shop --yes
tdk up shop --dry-run
tdk up shop
tdk doctor checks Docker, Tilt, and ports. tdk ui is a terminal dashboard for the running services. tdk config verify catches drift if someone hand-edits a generated file.
It is local dev only. Production stays on Helm, Argo CD, or Kustomize. Core is MIT and does not need a key. You need Docker and Tilt. macOS and Linux work directly. Windows needs WSL2 Ubuntu. Native Windows can inspect, not start the stack.
Repo: <a href="https://github.com/tdk-landscape/tdk-cli-core">https://github.com/tdk-landscape/tdk-cli-core</a>
If Compose or Tilt already works for you, would a service.json still be worth it, or is that just another file to keep in sync?</p>
]]></content:encoded></item><item><title><![CDATA[The Largest Architecture Diagram You Have Never Seen: TDK CLI, End to End
]]></title><description><![CDATA[Most tool documentation shows one box and one arrow. TDK CLI is bigger than that. A single tdk up passes through TypeScript commands, Starlark discovery…]]></description><link>https://tdk-cli.hashnode.dev/the-largest-architecture-diagram-you-have-never-seen-tdk-cli-end-to-end</link><guid isPermaLink="true">https://tdk-cli.hashnode.dev/the-largest-architecture-diagram-you-have-never-seen-tdk-cli-end-to-end</guid><dc:creator><![CDATA[odykyi]]></dc:creator><pubDate>Tue, 20 Oct 2026 11:10:21 GMT</pubDate><content:encoded><![CDATA[<p>Most tool documentation shows one box and one arrow. TDK CLI is bigger than that. A single <code>tdk up</code> passes through TypeScript commands, Starlark discovery and generators, a generated Tiltfile, Docker containers, a Traefik proxy, and a set of checks that run before anything starts.</p>
<p>This article draws the whole system in one Mermaid diagram, then walks through it. The diagram follows the repository's own maintainer guide (<code>docs/TOPOLOGY.md</code>) and the folders I read in the source. Some labels are summaries, so check the names against the repo before you rely on a single one.</p>
<h2>The diagram</h2>
<pre><code class="language-mermaid">flowchart TD
    %% ---------- People and clients ----------
    DEV["Developer at a terminal"]
    AGENT["AI agent: Codex or Claude Code"]
    IDE["IDE and editor"]

    %% ---------- Inputs you own ----------
    subgraph INPUTS["Inputs you own"]
        PROJ[".tdk/project.json"]
        SVC["service.json per service"]
        SRC["Application source code"]
        TILTF["Project Tiltfile"]
        ENVF["Environment files and secrets"]
    end

    %% ---------- CLI in TypeScript ----------
    subgraph CLI["CLI in TypeScript: cli/src"]
        direction TB
        CMDS["commands: project, resource, up, down, status, logs, ui, doctor, config, mcp"]
        CFG["config and types"]
        GEN["generator: Handlebars project files"]
        FEPROV["frontend-frameworks: react, vue, svelte, solid, preact, lit, qwik, vanilla, tanstack-router"]
        BEPROV["backend-languages: bun, go, python, rust"]
        BFW["backend-frameworks: hono, express, elysia, fastify, nestjs, koa, h3, mcp"]
        MCPSRV["mcp server over stdio: doctor, up, down, status, logs, resource_list"]
        UI["ui: terminal dashboard"]
        UTIL["utils and components"]
    end

    %% ---------- CLI templates ----------
    subgraph TPL["CLI templates: cli/templates"]
        TPLT["Tiltfile.hbs"]
        TPLS["spec.master.hbs"]
        TPLSTACK["TILT_TECH_STACK.star.hbs"]
        TPLDEF["TILT_RESOURCE_DEFAULTS.star.hbs"]
    end

    %% ---------- Discovery in Starlark ----------
    subgraph DISC["Discovery in Starlark: discovery/"]
        DORCH["discovery_orchestrator.star"]
        DREG["registry.star"]
        DMAN["manifest scan and validation"]
        DSNAP["snapshots"]
    end

    %% ---------- Engine in Starlark ----------
    subgraph ENG["Engine in Starlark: engine/topologies"]
        direction TB
        subgraph GENS["tilt/generators"]
            GIDX["index.star"]
            GVITE["Vite and TypeScript configs"]
            GNPM["npm and bunfig config"]
            GPRISMA["Prisma config"]
            GENV["environment files and API helpers"]
            GAGENTS["AGENTS.md notice"]
        end
        subgraph RES["tilt/resources"]
            RDECL["resource declaration"]
            RORCH["orchestrator and generators"]
            RDEP["startup order and dependsOn"]
            RTRIG["triggers and live update"]
        end
        subgraph MAN["tilt/manifest"]
            MLOAD["manifest loader"]
            MSCHEMA["schema and constants"]
        end
        subgraph PLAT["platform"]
            PDOCK["docker: language and frontend Dockerfiles"]
            PNET["networking and Traefik"]
            PINFRA["Postgres and optional infra"]
        end
    end

    %% ---------- Generated runtime files ----------
    subgraph GENOUT["Generated per service: .autogenerated"]
        DFILE["Dockerfile.app.autogenerated"]
        NGINX["nginx.autogenerated.conf"]
        VCONF["vite and tsconfig files"]
        APIC["api-client.ts and env.ts"]
        SNAP[".tdk-contract snapshots"]
        SYAML["service.yaml projection"]
    end

    %% ---------- Checks ----------
    subgraph CHECKS["Checks"]
        DOCTOR["tdk doctor: host and canUp"]
        DRIFT["drift check: generated files vs snapshots"]
        DRYRUN["tdk up --dry-run: plan only"]
        MIGWARN["doctor warning: migration in start script"]
        READY["readiness: status and up JSON"]
    end

    %% ---------- Runtime ----------
    subgraph RUNTIME["Runtime on your machine"]
        TILT["Tilt: builds, watches, live-updates"]
        DOCKER["Docker engine"]
        TRAEFIK["Traefik proxy"]
        PG["PostgreSQL"]
        SVCS["Service containers: frontends, APIs, workers, MCP servers"]
        NATS["NATS messaging when enabled"]
    end

    %% ---------- Outside the local loop ----------
    subgraph PROD["Outside TDK: production"]
        HELM["Helm"]
        ARGO["Argo CD"]
        KUST["Kustomize"]
    end

    %% ---------- Flows ----------
    DEV --&gt; CMDS
    IDE --&gt; SRC
    AGENT --&gt; MCPSRV
    MCPSRV --&gt; CMDS

    CMDS --&gt; GEN
    GEN --&gt; TPL
    CMDS --&gt; FEPROV
    CMDS --&gt; BEPROV
    CMDS --&gt; BFW
    CMDS --&gt; UI
    CMDS --&gt; CFG
    CFG --&gt; UTIL

    PROJ --&gt; DORCH
    SVC --&gt; DORCH
    DORCH --&gt; DREG
    DORCH --&gt; DMAN
    DMAN --&gt; MLOAD
    DREG --&gt; DSNAP

    TILTF --&gt; DORCH
    TILTF --&gt; RDECL
    RDECL --&gt; RORCH
    RORCH --&gt; GIDX
    GIDX --&gt; GVITE
    GIDX --&gt; GNPM
    GIDX --&gt; GPRISMA
    GIDX --&gt; GENV
    GIDX --&gt; GAGENTS
    RORCH --&gt; RDEP
    RDEP --&gt; RTRIG
    MLOAD --&gt; MSCHEMA
    RORCH --&gt; PDOCK
    RORCH --&gt; PNET
    RORCH --&gt; PINFRA

    GENS --&gt; GENOUT
    PDOCK --&gt; DFILE
    PNET --&gt; NGINX
    GVITE --&gt; VCONF
    GENV --&gt; APIC
    GENOUT --&gt; SNAP
    GENOUT --&gt; SYAML

    CMDS --&gt; DOCTOR
    SNAP --&gt; DRIFT
    DRIFT --&gt; TILT
    CMDS --&gt; DRYRUN
    RORCH --&gt; MIGWARN
    TILT --&gt; READY

    SRC --&gt; TILT
    ENVF --&gt; TILT
    TILT --&gt; DOCKER
    DOCKER --&gt; TRAEFIK
    DOCKER --&gt; PG
    DOCKER --&gt; SVCS
    DOCKER --&gt; NATS
    TRAEFIK --&gt; SVCS
    SVCS --&gt; PG
    SVCS --&gt; NATS

    HELM --&gt; ARGO
    KUST --&gt; ARGO

    %% ---------- Styling ----------
    classDef cli fill:#e8f1ff,stroke:#1d4ed8,color:#0f172a
    classDef engine fill:#fff4e5,stroke:#c2410c,color:#0f172a
    classDef runtime fill:#e8fbef,stroke:#15803d,color:#0f172a
    classDef check fill:#fdecec,stroke:#b91c1c,color:#0f172a
    classDef prod fill:#f3f4f6,stroke:#6b7280,color:#0f172a
    class CMDS,CFG,GEN,FEPROV,BEPROV,BFW,MCPSRV,UI,UTIL cli
    class DORCH,DREG,DMAN,DSNAP,GIDX,RDECL,RORCH,RDEP,RTRIG,MLOAD,MSCHEMA,PDOCK,PNET,PINFRA engine
    class TILT,DOCKER,TRAEFIK,PG,SVCS,NATS runtime
    class DOCTOR,DRIFT,DRYRUN,MIGWARN,READY check
    class HELM,ARGO,KUST prod
</code></pre>
<h2>How to read it</h2>
<p>Start at the top left. A developer, or an agent over MCP, enters the CLI. The CLI has three jobs: scaffolding files through templates and providers, reading the project's commands, and starting the stack.</p>
<p>The middle of the diagram is the two-stage generation the maintainer guide describes. The CLI writes starter files in TypeScript. At Tilt time, Starlark discovery reads each <code>service.json</code>, and the engine's generators write the runtime files under <code>.autogenerated/</code>. Those files are what Docker and Tilt run.</p>
<p>The right side shows the checks. <code>doctor</code> answers whether the machine can run the stack. The drift check compares generated files with their snapshots before startup. The dry run prints the plan. The readiness output tells you, or an agent, when a service is ready.</p>
<p>The bottom shows the runtime: Tilt drives Docker, Docker runs the Traefik proxy, Postgres, the service containers, and NATS when it is enabled. Production sits outside the loop. The diagram ends with Helm, Argo CD, and Kustomize, because TDK does not generate cluster manifests by default.</p>
<h2>Things the diagram leaves out</h2>
<p>It does not show every module or every generator. The <code>.tdk-contract</code> snapshots, the optional observability stacks, and the golden image layer are simplified or omitted. Use the repo's topology guide when you need the full list.</p>
<h2>Summary</h2>
<p>TDK CLI is a loop: TypeScript commands write project files, Starlark generators turn <code>service.json</code> into runtime files, checks confirm the result, and Docker and Tilt run it. Keep the inputs in your hands, treat the generated files as output, and let the checks tell you when something has drifted.</p>
]]></content:encoded></item><item><title><![CDATA[Everything You Need to Know About Code Review for AI-Generated Code
]]></title><description><![CDATA[AI-generated code tends to look tidy. The names are sensible, the structure is familiar, and the comments read well. That polish is the risk. A reviewer…]]></description><link>https://tdk-cli.hashnode.dev/everything-you-need-to-know-about-code-review-for-ai-generated-code</link><guid isPermaLink="true">https://tdk-cli.hashnode.dev/everything-you-need-to-know-about-code-review-for-ai-generated-code</guid><dc:creator><![CDATA[odykyi]]></dc:creator><pubDate>Tue, 20 Oct 2026 11:09:32 GMT</pubDate><content:encoded><![CDATA[<p>AI-generated code tends to look tidy. The names are sensible, the structure is familiar, and the comments read well. That polish is the risk. A reviewer who relaxes because the code looks right will miss the errors that matter most.</p>
<p>Good review of generated code asks different questions from review of code written by a colleague who knows the system.</p>
<h2>Check the claims first</h2>
<p>Start with what the change says it does. Compare the description, the tests, and the diff. If the author says "adds retry logic" and the diff does not touch the call site, something is missing. Agents sometimes report success for work they did not complete.</p>
<h2>Check what is not there</h2>
<p>Generated code often omits the things a human would remember: timeouts, input validation, error handling for the failure path, cleanup of resources, and logging that helps someone debug at night. Look for what should be present and is not.</p>
<h2>Check the dependencies</h2>
<p>An agent may add a package you did not choose, or pick a version that does not match the rest of the project. Review every change to the manifest and the lockfile. Confirm each new package is one you would have chosen, and check that its name is spelled correctly. Typosquatted packages are a real risk.</p>
<h2>Check the data and the secrets</h2>
<p>Search the diff for keys, tokens, and connection strings. Check what data the code reads, stores, or sends, and where it goes. Generated code is good at moving data to convenient places, which is not always the right place.</p>
<h2>Check the edges</h2>
<p>Ask what happens with empty input, a very large input, a slow dependency, and two requests at once. These are the cases generated code most often skips.</p>
<h2>Keep the review small</h2>
<p>A reviewer can check a few hundred lines carefully. Ten thousand generated lines get a skim. If an agent produced a large change, ask it to split the work into reviewable pieces, each with its own checks.</p>
<h2>Use tools to reduce the load</h2>
<p>Linters, type checkers, and tests catch a large share of the mechanical errors, so the human reviewer can focus on intent and design. Run them before review, and require them to pass.</p>
<h2>Record what you reviewed</h2>
<p>For changes that matter, keep a short note: what was checked, what was tested, and what remains unverified. That note is useful when something fails later, and it discourages approval by habit.</p>
<h2>Summary</h2>
<p>Review AI-generated code by checking the claims, the omissions, the dependencies, the secrets, and the edges, in that order. Keep each review small, let tools handle the mechanical checks, and write down what you verified. Speed of generation does not change the standard a change must meet.</p>
]]></content:encoded></item><item><title><![CDATA[What Really Happens When You Type tdk up: A Sequence Diagram of TDK CLI
]]></title><description><![CDATA[The first architecture diagram showed the parts of TDK CLI. This one shows time: what happens, in order, after you type tdk up. Knowing the order tells you…]]></description><link>https://tdk-cli.hashnode.dev/what-really-happens-when-you-type-tdk-up-a-sequence-diagram-of-tdk-cli</link><guid isPermaLink="true">https://tdk-cli.hashnode.dev/what-really-happens-when-you-type-tdk-up-a-sequence-diagram-of-tdk-cli</guid><dc:creator><![CDATA[odykyi]]></dc:creator><pubDate>Tue, 20 Oct 2026 11:08:57 GMT</pubDate><content:encoded><![CDATA[<p>The first architecture diagram showed the parts of TDK CLI. This one shows time: what happens, in order, after you type <code>tdk up</code>. Knowing the order tells you where a start can stop, and which message to read when it does.</p>
<p>The sequence below follows the repo's documented behaviour: the host check, the drift check before Tilt starts, the Starlark generation at Tilt load time, readiness, and the JSON result. Some steps are summarised, so check them against the code and the docs before you rely on one exact message.</p>
<h2>The sequence</h2>
<pre><code class="language-mermaid">sequenceDiagram
    autonumber
    actor Dev as Developer
    participant Agent as AI agent over MCP
    participant CLI as tdk CLI (TypeScript)
    participant Host as Host and container runtime
    participant Snap as Snapshots in .tdk-contract
    participant Tilt as Tilt
    participant Disc as Discovery (Starlark)
    participant Eng as Engine generators (Starlark)
    participant Dock as Docker
    participant Svc as Service containers

    Dev-&gt;&gt;CLI: tdk up (or agent calls up)
    Agent-&gt;&gt;CLI: up (MCP tool runs tdk up --json)

    CLI-&gt;&gt;Host: check host type and container runtime
    alt canUp is false
        Host--&gt;&gt;CLI: no Docker, WebContainer, or Windows opt-in missing
        CLI--&gt;&gt;Dev: exit non-zero, tell the reason, do not spawn Tilt
    else canUp is true
        CLI-&gt;&gt;Snap: compare generated files with saved snapshots
        alt a generated file was hand-edited
            Snap--&gt;&gt;CLI: drift found, name the file
            CLI--&gt;&gt;Dev: block the start, fix the source and retry
        else no drift
            CLI-&gt;&gt;Tilt: spawn Tilt with the project Tiltfile
            Tilt-&gt;&gt;Disc: load service.json files
            Disc--&gt;&gt;Tilt: resources, stacks, dependsOn
            Tilt-&gt;&gt;Eng: generate per-service runtime files
            Eng--&gt;&gt;Tilt: write .autogenerated and service.yaml
            Tilt-&gt;&gt;Dock: build images, start containers in order
            Dock-&gt;&gt;Svc: start proxy, Postgres, services
            Svc--&gt;&gt;Tilt: health route answers
            Tilt--&gt;&gt;CLI: resources report ready or failed
            CLI--&gt;&gt;Agent: ok true, or ok false with errors
            CLI--&gt;&gt;Dev: TDK is up, with URLs and ports
        end
    end

    Note over Agent,CLI: The agent polls status until readiness.ready is true
    Agent-&gt;&gt;CLI: status
    CLI--&gt;&gt;Agent: readiness ready, pending, or failures
    Dev-&gt;&gt;CLI: tdk down
    CLI-&gt;&gt;Tilt: stop resources
    Tilt-&gt;&gt;Dock: stop and remove containers
</code></pre>
<h2>The steps that can stop you</h2>
<p>Four steps can stop a start, and each one tells you something different.</p>
<p><strong>The host check.</strong> If <code>canUp</code> is false, the machine is the problem. No change to your project will help until the host has a working container runtime. The command exits without starting Tilt.</p>
<p><strong>The drift check.</strong> A hand edit to a file under <code>.autogenerated/</code> blocks the start and names the file. The fix is upstream: change <code>service.json</code> or the generator, then start again. This check runs before Tilt is spawned, so nothing has been built yet.</p>
<p><strong>Readiness.</strong> <code>up</code> returns before the stack is ready, because a build can take longer than one command. The result tells you whether every resource is built, running, and healthy, or which one failed. <code>tdk status --json</code> answers the same question at any time.</p>
<p><strong>The first failed resource.</strong> A failure in one service usually stops the ones that depend on it. Read the logs for the first failed resource, not the last. <code>tdk logs --json --service &lt;name&gt; --tail 200</code> returns a bounded snapshot.</p>
<h2>Where the agent fits</h2>
<p>An agent does not replace this sequence. It calls the same commands through the MCP server. The useful part for the agent is the loop: call <code>up</code>, poll <code>status</code> until ready, read <code>logs</code> for any failure, then stop. The sequence above shows why the poll is needed. <code>up</code> returns before readiness.</p>
<h2>Stopping cleanly</h2>
<p><code>tdk down</code> reverses the lifecycle: Tilt stops the resources, and Docker removes the containers. Run it when you finish. A stack left running keeps its ports, and the next <code>up</code> may refuse to start while an old Tilt still answers on its port.</p>
<h2>Summary</h2>
<p>One <code>tdk up</code> is a short chain of checks before any container starts: host, drift, then generation and readiness. Each check has its own message, and each message points at the fix. Read them in order, and most starts become a matter of reading the first line that failed.</p>
]]></content:encoded></item><item><title><![CDATA[Forget MVC. The New Era Is PSR (Project Stack Resource)
]]></title><description><![CDATA[You’re still thinking in MVC. Controllers, models, views, “where does this function live?”, “which file owns the routing?” — that mental model made sense…]]></description><link>https://tdk-cli.hashnode.dev/forget-mvc-the-new-era-is-psr-project-stack-resource</link><guid isPermaLink="true">https://tdk-cli.hashnode.dev/forget-mvc-the-new-era-is-psr-project-stack-resource</guid><dc:creator><![CDATA[odykyi]]></dc:creator><pubDate>Tue, 20 Oct 2026 11:08:05 GMT</pubDate><content:encoded><![CDATA[<p>You’re still thinking in MVC.</p>
<p>Controllers, models, views, “where does this function live?”, “which file owns the routing?” — that mental model made sense when the unit of work was a single application. It starts falling apart the moment you have more than a handful of services that need to run together locally.</p>
<p>The useful unit of work is no longer a function or a controller. It’s a <strong>resource</strong> that belongs to a <strong>stack</strong> inside a <strong>project</strong>.</p>
<h3>The Old Era vs the New One</h3>
<table>
<thead>
<tr>
<th>Era</th>
<th>Mental model</th>
<th>What you maintain by hand</th>
<th>What breaks at scale</th>
</tr>
</thead>
<tbody><tr>
<td>MVC</td>
<td>Controllers / Models / Views</td>
<td>Routes, services, wiring inside one app</td>
<td>Multi-service local reality</td>
</tr>
<tr>
<td>Manual microservices</td>
<td>Dockerfiles + Compose + scripts</td>
<td>Everything surrounding the code</td>
<td>Consistency, onboarding, drift</td>
</tr>
<tr>
<td><strong>PSR</strong></td>
<td><strong>Project → Stack → Resource</strong></td>
<td><code>service.json</code> + app code</td>
<td>Almost nothing local</td>
</tr>
</tbody></table>
<p>If you’re still spending afternoons reading or rewriting Dockerfiles, Tiltfiles, nginx configs, Vite configs, and health-check plumbing, you’re operating in the previous era.</p>
<h3>Project → Stack → Resource</h3>
<pre><code class="language-mermaid">flowchart LR
    P["Project&lt;br/&gt;.tdk/project.json"] --&gt; S1["Stack: shop"]
    P --&gt; S2["Stack: billing"]
    S1 --&gt; R1["orders-api&lt;br/&gt;backend"]
    S1 --&gt; R2["storefront-web&lt;br/&gt;frontend"]
    S2 --&gt; R3["checkout-api&lt;br/&gt;backend"]
</code></pre>
<ul>
<li><strong>Project</strong> owns the overall landscape and phases.</li>
<li><strong>Stack</strong> is a business slice you can start on its own (<code>tdk up shop</code>).</li>
<li><strong>Resource</strong> is one service (backend, frontend, worker, migrator, etc.).</li>
</ul>
<p>You declare the resource once:</p>
<pre><code class="language-json">{
  "$schema": "https://tdk-landscape.github.io/schema.service.json",
  "schemaVersion": 1,
  "appName": "orders-api",
  "appType": "backend",
  "stack": "shop",
  "port": 4000,
  "healthCheckPath": "/health",
  "dependsOn": []
}
</code></pre>
<p>Everything else is derived.</p>
<h3>You Don’t Need to Read the Functions Anymore</h3>
<p>This is the part that feels wrong at first if you grew up in the MVC era.</p>
<p>In the old model you had to read the functions because the functions <em>were</em> the system. The routing, the dependency wiring, the startup order, the config — all of it lived in code you were expected to understand line by line.</p>
<p>In the PSR model the local infrastructure is a generated artifact. TDK produces the Dockerfile, the Tiltfile, the Traefik routes, the live-update rules, the nginx/Vite/tsconfig/env files, the API client, the health probes, and the Postgres wiring from the contract. You stop treating those files as something you carefully author and constantly re-read.</p>
<pre><code class="language-mermaid">flowchart TD
    A["Write service.json&lt;br/&gt;+ app code"] --&gt; B["tdk up"]
    B --&gt; C{"Drift check"}
    C --&gt;|Clean| D["Tilt + Docker&lt;br/&gt;Hot reload"]
    C --&gt;|Hand edit detected| E["Exit 2&lt;br/&gt;List files"]
    E --&gt; F["tdk config regenerate"]
    E --&gt; G["--ignore-drift"]
</code></pre>
<p>Hand-edits are not silently overwritten. <code>tdk up</code> exits with code 2 and tells you exactly which generated files drifted. You either regenerate from the contract or explicitly keep the customization. The source of truth stays the small declarative file and your application code.</p>
<h3>Why This Is the Actual Upgrade</h3>
<p>AI made writing application code cheap. It did not make multi-service local infrastructure consistent. Generators that treat their output as derived artifacts (and refuse to quietly wipe your changes) close that gap.</p>
<p>You’re falling behind if:</p>
<ul>
<li>You still hand-maintain a <code>docker-compose.yml</code> for more than a couple of services.</li>
<li>You treat the Tiltfile as source instead of generated.</li>
<li>You spend time reading generated nginx, Vite, or Dockerfile logic instead of changing the contract.</li>
<li>Your “local setup” is a wiki page instead of <code>tdk doctor</code> + <code>tdk up</code>.</li>
</ul>
<p>The MVC era taught us to organize code inside one process. The PSR era organizes <strong>resources</strong> that can be started, stopped, and hot-reloaded as slices of a larger system — without forcing you to re-read the plumbing every time the generator improves.</p>
<p>The functions still exist. You just stop needing to live inside them for the local infrastructure layer.</p>
<h3>Getting Started</h3>
<pre><code class="language-bash">npm install -g @tdk-landscape/tdk-cli-core
tdk doctor
tdk project --yes
tdk resource orders-api --type backend --stack shop --yes
tdk up shop
</code></pre>
<p>MVC got you this far.<br />Project → Stack → Resource is how you stop maintaining the local stack by hand.</p>
]]></content:encoded></item></channel></rss>