DEV Community

Cover image for Everything You Need to Know About Agents
tdk-cli
tdk-cli

Posted on

Everything You Need to Know About Agents

"Agent" is one of the most overused words in software right now. It can mean a chatbot with a few tools, a script that loops until a task is done, or a system that plans, acts, and checks its own work over many steps. This article defines the term, explains how agents are built, lists the failure modes that matter, and then shows how to give an agent real control over a local TDK stack.

What is an agent?

An agent is a language model placed in a loop with tools. Instead of answering once, it:

  1. reads a goal and the current state,
  2. decides on the next action,
  3. calls a tool and reads the result,
  4. repeats until the goal is met or it gives up.

The model supplies judgment; the tools supply the ability to act. A model that only writes text is a chatbot. A model that can run a command, read a file, or call an API and then use what it learned is an agent.

Three parts define most agents:

  • The model, which chooses actions.
  • Tools, which are functions the agent can call: read a file, run a command, query a database, start a service.
  • The loop and its state, which keeps the history of what was tried and what happened.

Agents versus workflows

Not every multi-step AI system is an agent. The distinction matters because it decides how much you trust the system.

  • A workflow follows a path you wrote. Step A calls the model, step B parses the output, step C writes a file. The model fills in content, but you control the order.
  • An agent chooses its own path. It decides which tool to call next and when to stop.

Prefer a workflow when the steps are known in advance. Reach for an agent when the path depends on what the agent discovers, such as debugging a failing service where the next check depends on the last error.

How agents are built

Most agent systems share a small set of design decisions.

Tools are the interface

A tool has a name, a description the model reads, a schema for its arguments, and an implementation. Clear descriptions matter as much as code. The model chooses tools by reading their descriptions, so a vague description leads to wrong calls.

Good tool design:

  • one clear purpose per tool,
  • narrow arguments with validation,
  • structured output the model can parse,
  • errors that say what went wrong and what to try next.

Context is limited

The model sees only what is in its context window. Long tool outputs, such as full log files, push out earlier information. Design tools to return bounded, relevant results. A tool that returns the last 200 log lines is easier for an agent to use than one that dumps the whole file.

The loop needs a stop condition

An agent without a stop condition can loop forever or spend money without progress. Define:

  • a success check (tests pass, the service answers 200),
  • a maximum number of steps or time,
  • what to do when stuck (report back to the human).

Human checkpoints

For actions that are hard to undo, such as deleting data, sending messages, or deploying, require a person to approve. Agents are fast; a wrong destructive action is fast too.

Where agents go wrong

Understanding failure modes is more useful than admiring capabilities.

  • Wrong tool, wrong arguments. The model calls the right tool with a made-up value. Validate arguments strictly.
  • Confident wrong answers. The agent reports success without checking. Make the success check a tool call, not the model's opinion.
  • Looping. The agent repeats the same failing action. Detect repeated calls and stop.
  • Scope creep. The agent "fixes" things nobody asked it to touch. Limit what it can write and where.
  • Stale state. The agent acts on a view of the world that changed. Re-read state before acting on it.
  • Over-trust in logs. A running process is not a healthy service. Check readiness, not just that something started.

Safe defaults for agents

  • Give the agent the fewest tools that let it finish the task.
  • Make read-only tools the default; make destructive tools explicit.
  • Run it in a project directory, not your home directory.
  • Log every tool call so you can review what happened.
  • Test the loop on a throwaway project before you trust it with real work.

Agents and local infrastructure

Agents are useful for infrastructure work because the work is loop-shaped: start the stack, check which service failed, read its logs, fix the configuration, start again. A human can do this, but it is tedious. An agent can do it quickly, if it has the right tools and can tell when it has succeeded.

The hard part is giving the agent tools that are reliable. A local stack has a lot of moving parts. If the agent must guess how to start Docker, which ports are in use, and where the logs are, it will fail often. The fix is to expose the stack through tools with clear results.

That is what TDK CLI does.

How TDK CLI gives agents control of a local stack

TDK CLI is not an AI model and does not decide what to build. It is a local tool that describes a stack in service.json files and runs it with Docker and Tilt. What makes it useful to agents is that every operation has a machine-readable form, and the CLI can run as a Model Context Protocol (MCP) server.

There are three pieces to use together.

1. Machine-readable commands

Most TDK commands accept --json and print one versioned object instead of human text. The ones an agent needs most:

  • tdk doctor --json reports the host (local, wsl2, devcontainer, codespaces, webcontainer, native-windows), whether a container runtime is reachable, and whether tdk up can work here (canUp).
  • tdk up --json starts the stack and prints ok: true once every resource is built, running, and healthy, or ok: false with errors when something fails. Tilt keeps running after the object is printed, so the agent should run this in the background.
  • tdk status --json reports ports, URLs, and readiness (data.tilt.readiness with ready, pending, failures).
  • tdk logs --json --service <name> --tail <n> prints the most recent lines as bounded, structured entries, so the agent does not read unbounded output.
  • tdk down --json stops the stack and reports the result.

Errors are typed, too. Examples include UNKNOWN_SERVICE, TILT_ALREADY_RUNNING, and TILT_NOT_RUNNING, each with an exit code. An agent can branch on the code instead of parsing English.

2. The TDK MCP server

tdk mcp runs a Model Context Protocol server over stdio. There is no separate package and no hosted endpoint; the CLI runs locally and the client talks to it over stdin and stdout.

It exposes six tools: doctor, up, down, status, logs, and resource_list. Each one runs the matching --json command, so the MCP behaves like the CLI. Arguments are validated before anything runs: names may use only letters, digits, ., _ and -.

Two details matter for agents:

  • up starts Tilt detached and returns without waiting for readiness, since a build can outlast a single tool call. The agent must poll status until data.tilt.readiness.ready is true. That gives you a success check.
  • logs is a snapshot, not a stream. The agent reads the recent lines, decides, and calls again.

3. An MCP service you can build with TDK

If you want to give your own application an agent interface, TDK can scaffold an MCP server as a service in your stack. It is a resource type called mcp, and it uses a Bun-based scaffold with the MCP SDK already wired in:

tdk resource support-tools --type mcp
Enter fullscreen mode Exit fullscreen mode

I inferred this command shape from the CLI source (cli/src/backend-frameworks/registry.ts, which treats mcp as its own resource type). Check tdk resource --help in your version before you rely on it.

The generated index.ts creates an MCP server with one placeholder tool, echo, and serves it over HTTP with a fresh server per request, so the endpoint has no session to lose when the container restarts. Replace echo with your own tools, such as "list open orders" or "restart the worker", and delete the placeholder.

Because it is a service like any other, tdk up starts it with the rest of the stack, Traefik routes to it, and Tilt live-updates it when you edit the code.

How to connect an agent to TDK, step by step

This is the practical part. It assumes you already have a TDK project with at least one service.

Step 1: Install TDK CLI

npm install -g @tdk-landscape/tdk-cli-core
# or, on macOS/Linux
curl -fsSL https://tdk-landscape.github.io/install.sh | sh
tdk --version
Enter fullscreen mode Exit fullscreen mode

Node.js 22.12 or newer is required for the npm route.

Step 2: Check the host

Run the doctor before you hand anything to an agent:

tdk doctor --json
Enter fullscreen mode Exit fullscreen mode

Look at data.host.containerRuntimeReachable and data.host.canUp. If canUp is false, the agent cannot start the stack from this machine, and no amount of retrying will fix it. On a WebContainer, for example, there is no Docker daemon, so the agent must run on a machine that has one.

Step 3: Connect the agent to the MCP server

The MCP server must start from the directory that contains .tdk/project.json. For Codex, add a project-scoped entry to .codex/config.toml:

[mcp_servers.tdk]
command = "tdk"
args = ["mcp"]
cwd = "/absolute/path/to/your/tdk-project"
Enter fullscreen mode Exit fullscreen mode

For Claude Code, follow the Claude Code section of the TDK agent tooling guide. The principle is the same: command tdk, argument mcp, working directory set to the project.

Some clients also accept the generic form, which works for most MCP hosts:

{ "mcpServers": { "tdk": { "command": "tdk", "args": ["mcp"] } } }
Enter fullscreen mode Exit fullscreen mode

Set the working directory in the client, because a server started from the wrong folder cannot find the project.

Step 4: Ask for outcomes, not commands

Once connected, you can ask in plain language. Good requests describe the result:

  • "Run TDK doctor and tell me what needs fixing before startup."
  • "Start only the web service and its dependencies, then check status."
  • "Show the latest five minutes of API logs."
  • "Stop the stack."

The agent then calls doctor, up, status, logs, and down in the right order.

Step 5: Write the loop the agent should follow

Give the agent an explicit procedure, so it does not improvise. A working one for starting a stack:

  1. Call doctor. If canUp is false, stop and report why.
  2. Call up with the services you need.
  3. Call status repeatedly until readiness.ready is true, or until failures is non-empty.
  4. If there are failures, call logs for the failing service with a bounded tail.
  5. Report the result, with the URLs from status.

The stop condition is the readiness check, and the failure branch is explicit. Put this in your agent's instructions or in the project's AGENTS.md, so every session follows it.

Step 6: Stop cleanly

When the work is done, have the agent call down. A stack left running consumes memory and ports, and the next tdk up may refuse to start while an old Tilt still answers.

A complete example

Here is a small end-to-end flow for a project with a web frontend, an api backend, and a support-tools MCP service.

  1. You run tdk doctor yourself once, and it reports canUp: true.
  2. You open Codex in the project directory. The tdk MCP server is connected.
  3. You ask: "Start the API and the support tools, check they are ready, and show me any errors from the last five minutes."
  4. The agent calls up with only: ["api", "support-tools"]. TDK starts those services and their dependencies.
  5. The agent polls status until readiness is true. If api fails, it reads its logs with tail and reports the error line.
  6. You ask the agent to fix the error. It edits the code, Tilt live-updates the container, and the agent polls status again.
  7. When you are done, the agent calls down.

Every step has a result you can check. The agent does not need to guess whether the stack is up.

Limits to respect

  • TDK does not decide what to build. The agent or you decide the change; TDK runs and reports it.
  • tdk up is not instant. Builds can take minutes. Poll, do not assume.
  • Docker must be reachable. An agent on a host without a container runtime can only report the problem.
  • Do not expose the MCP to a network. It runs over stdio on your machine, which is the point. Keep it that way.
  • Destructive operations need a person. Stopping a stack is low-risk; deleting data, resetting volumes, or changing production configuration are not. Keep those with a human.
  • Production stays elsewhere. TDK is for the local inner loop. Deployment remains with Helm, Argo CD, or Kustomize.

Summary

An agent is a model in a loop with tools. Its usefulness depends on the quality of its tools and on a clear stop condition. Local infrastructure is a good place to use agents, because the work is repetitive, loop-shaped, and checkable. TDK CLI supports this with --json output on every key command, an MCP server started with tdk mcp, and a way to scaffold your own MCP tool service with tdk resource --type mcp. Connect the agent from the project directory, give it a readiness check as its success condition, and keep destructive actions with a person.

Top comments (1)

Collapse
 
mynameis0d3c53a3 profile image
mynameis •

Everything You Need to Know About Agents
"Agent" is one of the most overused words in software right now. It can mean a chatbot with a few tools, a script that loops until a task is done, or a system that plans, acts, and checks its own work over many steps. This article defines the term, explains how agents are built, lists the failure modes that matter, and then shows how to give an agent real control over a local TDK stack.

What is an agent?
An agent is a language model placed in a loop with tools. Instead of answering once, it:

reads a goal and the current state,
decides on the next action,
calls a tool and reads the result,
repeats until the goal is met or it gives up.
The model supplies judgment; the tools supply the ability to act. A model that only writes text is a chatbot. A model that can run a command, read a file, or call an API and then use what it learned is an agent.

Three parts define most agents:

The model, which chooses actions.
Tools, which are functions the agent can call: read a file, run a command, query a database, start a service.
The loop and its state, which keeps the history of what was tried and what happened.