# Changelog
All notable changes to task-mcp will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [0.5.0] - 2026-04-14
### Added
- **`content` argument on `run` tool** — the `run` request now accepts an optional `content` field (`HashMap<String, String>`) for passing raw text to recipes without escaping. Each entry is delivered to the recipe as an environment variable named `TASK_MCP_CONTENT_{KEY}` (key uppercased). Values may contain newlines, carriage returns, and any valid UTF-8 — no sanitization is applied to values.
- **Content key validation** — content keys must match `[A-Za-z][A-Za-z0-9_]*` (start with an ASCII letter, then letters/digits/underscores only). Invalid keys produce a structured `InvalidContentKey` error before execution begins.
- **`TaskExecution.content` field** — execution logs now record the content map alongside the args map for traceability.
- **`TaskError::InvalidContentKey` variant** — distinct error variant for content key validation failures, with a message that includes the offending key and the required pattern.
### Changed
- **`validate_arg_value` now rejects only control characters** — shell metacharacters (`;`, `|`, `&&`, `||`, `` ` ``, `$(`, `${`) are no longer rejected. task-mcp invokes `just` via `Command::new("just").arg()`, which passes arguments directly to the OS without shell interpretation (OWASP MCP05:2025 safe pattern). Rejecting shell metacharacters at the MCP layer was guarding against a threat that does not exist in this execution path. `\n` and `\r` continue to be rejected as control characters inappropriate for structured tool input.
## [0.4.1] - 2026-04-12
### Added
- **`info` tool now includes `docs` field** — returns a link to `docs/execution-model.md` on GitHub, so MCP clients can access the execution model guide from any environment.
## [0.4.0] - 2026-04-12
### Changed (breaking)
- **Pattern A marker renamed `agent` → `allow-agent`** — the group name for the agent-safe attribute is now `[group('allow-agent')]`, matching the Pattern B comment marker `# [allow-agent]` literally. The previous `[group('agent')]` form (introduced incorrectly) is no longer recognized. Justfiles using the old form must be updated to the new spelling — there is no compatibility shim.
- **Built-in templates migrated to Pattern A** — `rust` and `vite-react` templates now generate `[group('allow-agent')]` attributes instead of `# [allow-agent]` doc comments. Recipe doc comments are placed on the line above the attribute, avoiding the Pattern B shadowing pitfall.
- **Allow-agent positioned as a security boundary** — README and server instructions clarify that `TASK_MCP_MODE=agent-only` is a guard, not a display filter: non-allow recipes never enter the agent context via MCP. Reading the justfile directly is acknowledged as a non-canonical bypass.
### Added
- **Guard-order invariant comment** — `list` tool now carries an inline comment marking the security guard application order (`mode` filter before functional group `filter`) as non-reorderable, to protect against future refactors.
- **Regression test** — guards that the bare `'agent'` literal is no longer recognized by `has_allow_agent_group_attribute`.
### Internal
- `has_group_agent_attribute` renamed to `has_allow_agent_group_attribute`.
## [0.3.0] - 2026-04-11
### Added
- **Lazy auto-session-start** — `init` / `list` / `run` now auto-start a session using the server's startup CWD when that directory is a ProjectRoot (contains `.git` or `justfile`). Callers no longer need an explicit `session_start` in the common case. The triggering response includes an `auto_session_start` field describing the chosen workdir, justfile, and mode.
- **Typed auto-start outcome** — internal `AutoStartOutcome` enum distinguishes `Started` / `AlreadyStarted` / `NotProjectRoot` / `CanonicalizeFailed` / `NotAllowed`, allowing actionable error messages for each failure mode.
### Fixed
- **Concurrent auto-start race** — a racing tool call initializing the session between the fast-path read and the slow-path write lock no longer surfaces a spurious `session not started` error; the `AlreadyStarted` variant is recovered as success with the existing workdir.
- **Vague error messages** — `session not started` errors now identify whether the cause was a non-ProjectRoot startup CWD, a `canonicalize` failure, or an `allowed_dirs` violation.
### Changed
- **`list` response shape (breaking)** — the `list` tool now always returns an object `{"recipes": [...], "auto_session_start"?: {...}}` instead of alternating between a bare array and a wrapper depending on whether auto-start fired. Clients that parsed the previous top-level array need to read `.recipes`.
## [0.2.1] - 2026-04-10
### Added
- **Recursive import resolution** — `read_justfile_with_imports` now follows `import` directives recursively with cycle detection via canonicalized paths; nested `# [allow-agent]` comments in imported files are correctly picked up
### Fixed
- **`--working-directory` flag** — `just` invocations now pass `--working-directory` in addition to `current_dir`, fixing import-relative path resolution when executing recipes via explicit justfile path
### Changed
- **`LazyLock<Regex>` for import pattern** — import regex compiled once as a static; removes per-call `Regex::new` and `.expect()`
## [0.1.0] - 2026-03-29
### Added
- **`init` tool** — generates a justfile with agent-safe recipes in the session working directory; supports `rust` and `vite-react` project types with built-in templates; accepts custom template files (path-traversal prevention restricts to workdir); fails if justfile already exists to prevent accidental overwrite
- **Built-in justfile templates** — `rust` (cargo fmt/clippy/test/build) and `vite-react` (npm lint/typecheck/test/build); all recipes tagged `[allow-agent]`
- **`TASK_MCP_INIT_TEMPLATE_FILE` config** — optional path to a custom justfile template; overridden by the `template_file` tool argument
- **`session_start` tool** — sets the working directory for the session; validates against `TASK_MCP_ALLOWED_DIRS` whitelist using canonicalized `Path::starts_with` boundary check; can be called again to change the working directory
- **`info` tool** — returns current session state: active workdir, resolved justfile path, and task mode; read-only, idempotent
- **`TASK_MCP_ALLOWED_DIRS` config** — comma-separated list of directory paths that are allowed as session working directories; if unset, any directory is accepted; paths are canonicalized on parse
- **Session-based workdir management** — `Arc<RwLock<Option<PathBuf>>>` guards `run` and `list` so they require `session_start` before execution (except `list` with an explicit `justfile` parameter)
- **`just` execution with explicit CWD** — `list_recipes` and `execute_recipe` now accept `workdir: Option<&Path>` and pass it to `Command::current_dir`; relative justfile paths are resolved relative to the active workdir
- **MCP server with stdio transport** — `task-mcp --mcp` starts the server; integrates with Claude Code and any MCP-compatible client
- **`list` tool** — lists justfile recipes filtered by `[allow-agent]` group attribute; supports optional group filter and justfile path override; returns name, description, parameters, and groups per recipe
- **`run` tool** — executes a named recipe with named arguments; enforces whitelist (only recipes visible via `list` can be run); configurable timeout (default 60 s)
- **`logs` tool** — retrieves in-memory execution logs; summary of the 10 most recent executions by default; full output by task UUID with optional `tail` line filter
- **`[allow-agent]` access control** — recipes must carry `[group('agent')]` attribute to be exposed in `agent-only` mode (default)
- **`all` mode** — set `TASK_MCP_MODE=all` to expose all non-private recipes regardless of group
- **Output truncation** — stdout/stderr capped at 100 KB; head+tail preserved when truncated; `truncated` flag in response
- **Argument sanitization** — shell metacharacters in argument values are rejected before execution
- **Execution timeout** — configurable per `run` call; hard-kill on expiry
- **`.task-mcp.env` support** — load `TASK_MCP_MODE` and `TASK_MCP_JUSTFILE` from a project-local env file
- **MCP tool annotations** — `list` and `logs` marked `read_only_hint=true`, `idempotent_hint=true`; `run` marked `destructive_hint=true`; all tools `open_world_hint=false`
- **`just --dump --dump-format json --unstable` based parsing** — no Tree-sitter dependency; parses recipe name, doc, attributes, and parameters
- **UUID-tagged executions** — each `run` returns a unique `id` for later retrieval via `logs`
- **Integration tests** — justfile fixture-based tests covering list/run/logs end-to-end
- **Unit tests** — config parsing, mode detection, model serialization, output truncation helpers