agentic-to-do is a self-contained Agent Application package that demonstrates every part of the v1 contract in one place: an APP.md manifest, a JSON-first CLI, application-owned state, a local skill for agents, and automated tests.
Source: davetist/agentapplications
What it demonstrates
agentic-to-do shows how to build an Agent Application that an agent can inspect and operate safely without relying on prompt memory:
APP.md as the contract — the manifest defines the CLI entry command, every command signature, output shape, state location, scheduling support, and confirmation requirements.
- JSON-first CLI — every command writes structured JSON to stdout. Errors also return JSON with a non-zero exit code, so agents can parse success and failure the same way.
- Application-owned state — to-do items are stored in
app/state/todos.json. The application manages reads and writes; agents interact only through the CLI.
- Stable IDs — items get IDs like
td_0001, td_0002 that persist across runs and are safe to reference in subsequent commands.
- Local skill —
skills/agentic-to-do-usage/SKILL.md gives agents concise operating guidance without embedding it in the manifest.
- Scheduling support — items accept an optional
--due-at ISO date, surfaced in both add and update.
- Confirmation guard —
remove requires --confirm so agents cannot delete items accidentally.
Package structure
agentic-to-do/
├── APP.md
├── app/
│ ├── cli.js
│ └── state/
│ └── todos.json
└── skills/
└── agentic-to-do-usage/
└── SKILL.md
| Path | Role |
|---|
APP.md | Manifest and CLI contract |
app/cli.js | JSON-first CLI entrypoint |
app/state/todos.json | Application-owned persistent state |
skills/agentic-to-do-usage/SKILL.md | Local skill for agent operating guidance |
The APP.md frontmatter
The manifest opens with a YAML frontmatter block that a runtime reads at catalog time:
schema: agentapplications/v1
kind: app
slug: agentic-to-do
name: Agentic To-Do
description: Self-contained persistent to-do list operated through a JSON-first CLI
version: 0.1.0
entry:
command: node app/cli.js
commands:
- add
- list
- get
- update
- complete
- remove
skills:
- agentic-to-do-usage
scheduling: supported
confirmationRequired:
- remove
CLI commands
Run any command from the package root with:
node app/cli.js <command> [...args]
add
node app/cli.js add <title> [--description <text>] [--due-at <iso-date>]
Creates an open to-do item. title is required. --description and --due-at are optional.
list
node app/cli.js list [--status all|open|completed]
Lists items filtered by status. Defaults to all when --status is omitted.
get
Fetches a single to-do item by its stable ID.
update
node app/cli.js update <id> [--title <text>] [--description <text>] [--due-at <iso-date>] [--clear-due-at]
Updates one or more mutable fields on an existing item. Pass --clear-due-at to remove a previously set due date.
complete
node app/cli.js complete <id>
Marks an item as completed. If the item is already completed, the command returns the item unchanged.
remove
node app/cli.js remove <id> --confirm
Deletes an item permanently. The --confirm flag is required because the operation is destructive.
JSON output
Every command writes JSON to stdout. You parse the same structure whether the command succeeded or failed.
Success
{
"ok": true,
"command": "list",
"count": 1,
"items": [
{
"id": "td_0001",
"title": "Write docs",
"description": "",
"status": "open",
"dueAt": "2026-04-05",
"createdAt": "2026-04-01T00:00:00.000Z",
"updatedAt": "2026-04-01T00:00:00.000Z",
"completedAt": null
}
]
}
Failure
When a command fails, the CLI writes a structured error payload and exits with a non-zero code:
{
"ok": false,
"error": {
"code": "CONFIRMATION_REQUIRED",
"message": "remove requires --confirm."
}
}
Always check the ok field first. A non-zero exit code means ok is false and the error object contains a machine-readable code and a human-readable message.
State model
The application stores all to-do items in app/state/todos.json. The file is created automatically on the first command if it does not exist.
IDs are stable and increment as td_0001, td_0002, and so on. Once assigned, an ID never changes.
Each item has the following fields:
| Field | Type | Description |
|---|
id | string | Stable identifier, e.g. td_0001 |
title | string | Required non-empty string |
description | string | Optional text, defaults to "" |
status | "open" or "completed" | Current state of the item |
dueAt | string or null | ISO-8601 date or datetime, or null |
createdAt | string | ISO-8601 timestamp set at creation |
updatedAt | string | ISO-8601 timestamp updated on every write |
completedAt | string or null | ISO-8601 timestamp set by complete, otherwise null |
Scheduling support
The manifest declares scheduling: supported. In practice, this means add and update both accept a --due-at flag that takes an ISO-8601 date or datetime string.
node app/cli.js add "Write tests" --due-at 2026-04-05
node app/cli.js update td_0001 --due-at 2026-04-10
node app/cli.js update td_0001 --clear-due-at
Confirmation rule
The manifest declares confirmationRequired: [remove]. The CLI enforces this by requiring --confirm on every remove call. Omitting the flag causes the command to fail with a CONFIRMATION_REQUIRED error rather than silently deleting data.
Isolated runs and testing
You can point the CLI at a different state file by setting the AGENTIC_TODO_STATE_FILE environment variable:
AGENTIC_TODO_STATE_FILE=/tmp/todos.json node app/cli.js add "Isolated item"
This is useful for tests and for running commands without touching the package’s default state.
Running the example
Run CLI commands
node app/cli.js add "Write APP.md"
node app/cli.js list --status open
node app/cli.js complete td_0001
node app/cli.js remove td_0001 --confirm