From a559d016419224f22ab2c3557af2263edd313c46 Mon Sep 17 00:00:00 2001 From: GENDOSU Date: Fri, 10 Jul 2026 14:36:05 +0000 Subject: [PATCH 1/6] docs: add documentation/cli-reference.md and .ja.md Migrate the Usage, JSON Output Format, and Usage Examples sections from README.md / README.ja.md into a dedicated CLI reference doc, following the existing documentation/ en/ja pairing convention. Adds a table of contents and places each command's JSON example once, under its own section. --- documentation/cli-reference.ja.md | 819 ++++++++++++++++++++++++++++++ documentation/cli-reference.md | 819 ++++++++++++++++++++++++++++++ 2 files changed, 1638 insertions(+) create mode 100644 documentation/cli-reference.ja.md create mode 100644 documentation/cli-reference.md diff --git a/documentation/cli-reference.ja.md b/documentation/cli-reference.ja.md new file mode 100644 index 00000000..9e564f6b --- /dev/null +++ b/documentation/cli-reference.ja.md @@ -0,0 +1,819 @@ +# CLIリファレンス + +agkanの全コマンド・オプション・JSON出力フォーマットを網羅したリファレンスです。 + +## 目次 + +- [使用方法](#使用方法) + - [プロジェクトの初期化](#プロジェクトの初期化) + - [タスクの作成](#タスクの作成) + - [タスク一覧の表示](#タスク一覧の表示) + - [タスクの検索](#タスクの検索) + - [タスク詳細の取得](#タスク詳細の取得) + - [タスクの更新](#タスクの更新) + - [親子関係の管理](#親子関係の管理) + - [ブロック関係の管理](#ブロック関係の管理) + - [タスクの削除](#タスクの削除) + - [タグ管理](#タグ管理) + - [タスクへのタグ付け](#タスクへのタグ付け) + - [メタデータの管理](#メタデータの管理) + - [タスクのカウント](#タスクのカウント) + - [カンバンボード (Web UI)](#カンバンボード-web-ui) + - [Claudeプロセスの状態確認](#claudeプロセスの状態確認) + - [設定確認](#設定確認) + - [ヘルプの表示](#ヘルプの表示) +- [JSON出力フォーマット](#json出力フォーマット) + - [対応コマンド](#対応コマンド) + - [出力構造](#出力構造) + - [一般的な使用例](#一般的な使用例) +- [使用例](#使用例) + - [親子関係を使った階層的なタスク管理](#親子関係を使った階層的なタスク管理) + - [ブロック関係を使った依存関係の管理](#ブロック関係を使った依存関係の管理) + - [タグを使ったタスク管理](#タグを使ったタスク管理) + +## 使用方法 + +### プロジェクトの初期化 + +プロジェクトディレクトリで `agkan init` を実行して agkan をセットアップします: + +```bash +agkan init +``` + +以下のファイルが作成されます: +- `.agkan.yml` — 設定ファイル +- `.agkan/` — データディレクトリ + +`agkan init` は `.claude/settings.local.json` に SessionStart hook も登録し、 +Claude Code のセッション開始時に最小限の agkan 使用ガイドを自動でロードします。 +hook は `agkan context --hook` を呼び出します。既存設定との競合を避けるため +冪等にマージし、関係のないキーには触れません。Claude Code を使わない場合は +生成されたファイルを無視しても問題ありません。 + +### タスクの作成 + +基本的なタスク作成: +```bash +agkan task add "タスクのタイトル" "タスクの説明" +``` + +オプション付きでタスク作成: +```bash +agkan task add "ログイン機能の実装" "ユーザー認証システムを実装" \ + --status ready \ + --author "developer-name" +``` + +親タスクを指定してタスク作成: +```bash +agkan task add "子タスク" "詳細な作業項目" --parent 1 +``` + +Markdownファイルからタスク作成: +```bash +agkan task add "設計書レビュー" --file ./design-doc.md --status backlog +``` + +タグ付きでタスク作成(カンマ区切りのタグ名またはID、同じコマンドで付与): +```bash +agkan task add "ログイン機能の実装" --tag "frontend,urgent" +``` + +JSON出力フォーマット: +```bash +agkan task add "Fix bug in login" --json +``` + +```json +{ + "success": true, + "task": { + "id": 1, + "title": "Fix bug in login", + "status": "backlog", + "body": null, + "author": null, + "parent_id": null, + "created_at": "2026-02-15T00:00:00.000Z", + "updated_at": "2026-02-15T00:00:00.000Z" + }, + "parent": null, + "blockedBy": [], + "blocking": [] +} +``` + +### タスク一覧の表示 + +全タスクを表示: +```bash +agkan task list +``` + +ツリー形式で表示(親子関係を含む): +```bash +agkan task list --tree +``` + +ルートタスクのみ表示(親を持たないタスク): +```bash +agkan task list --root-only +``` + +ステータスでフィルタリング: +```bash +agkan task list --status in_progress +``` + +作成者でフィルタリング: +```bash +agkan task list --author "developer-name" +``` + +複合フィルター: +```bash +agkan task list --status ready --author "developer-name" +``` + +タグでフィルタリング: +```bash +agkan task list --tag "frontend" +``` + +JSON出力フォーマット: +```bash +agkan task list --json +``` + +```json +{ + "tasks": [ + { + "id": 1, + "title": "Implement login feature", + "status": "in_progress", + "body": "Implement user authentication system", + "author": "developer-name", + "parent_id": null, + "created_at": "2026-02-15T00:00:00.000Z", + "updated_at": "2026-02-15T00:00:00.000Z" + }, + { + "id": 2, + "title": "Design review", + "status": "backlog", + "body": null, + "author": null, + "parent_id": null, + "created_at": "2026-02-15T00:00:00.000Z", + "updated_at": "2026-02-15T00:00:00.000Z" + } + ] +} +``` + +### タスクの検索 + +キーワードでタスクを検索(タイトルと本文を対象): +```bash +agkan task find "検索キーワード" +``` + +完了済みタスクも含めて検索: +```bash +agkan task find "検索キーワード" --all +``` + +注: デフォルトでは、`done`と`closed`のタスクは検索結果から除外されます。 + +JSON出力フォーマット: +```bash +agkan task find "login" --json +``` + +```json +{ + "tasks": [ + { + "id": 1, + "title": "Implement login feature", + "status": "in_progress", + "body": "Implement user authentication system", + "author": "developer-name", + "parent_id": null, + "created_at": "2026-02-15T00:00:00.000Z", + "updated_at": "2026-02-15T00:00:00.000Z" + } + ] +} +``` + +### タスク詳細の取得 + +```bash +agkan task get 1 +``` + +JSON出力フォーマット: +```bash +agkan task get 1 --json +``` + +```json +{ + "task": { + "id": 1, + "title": "Implement login feature", + "status": "in_progress", + "body": "Implement user authentication system", + "author": "developer-name", + "parent_id": null, + "created_at": "2026-02-15T00:00:00.000Z", + "updated_at": "2026-02-15T00:00:00.000Z" + } +} +``` + +### タスクの更新 + +ステータスを変更: +```bash +agkan task update 1 status done +``` + +タイトルを変更: +```bash +agkan task update 1 title "新しいタイトル" +``` + +本文を変更: +```bash +agkan task update 1 body "新しい説明文" +``` + +作成者を変更: +```bash +agkan task update 1 author "new-author" +``` + +### 親子関係の管理 + +親タスクの更新: +```bash +# タスク2の親をタスク1に設定 +agkan task update-parent 2 1 + +# タスク2の親を解除(孤立化) +agkan task update-parent 2 null +``` + +注意事項: +- 親タスクを削除すると、子タスクの親参照は自動的に解除されます(孤立化) +- 循環参照は自動的に検出され、エラーとなります + +JSON出力フォーマット: +```bash +agkan task update-parent 2 1 --json +``` + +```json +{ + "success": true, + "task": { + "id": 2, + "title": "Child Task", + "status": "backlog", + "body": null, + "author": null, + "parent_id": 1, + "created_at": "2026-02-15T00:00:00.000Z", + "updated_at": "2026-02-15T00:00:00.000Z" + }, + "parent": { + "id": 1, + "title": "Parent Task", + "status": "backlog", + "body": null, + "author": null, + "parent_id": null, + "created_at": "2026-02-15T00:00:00.000Z", + "updated_at": "2026-02-15T00:00:00.000Z" + } +} +``` + +### ブロック関係の管理 + +ブロック関係の追加(タスク1がタスク2をブロック): +```bash +agkan task block add 1 2 +``` + +ブロック関係の削除: +```bash +agkan task block remove 1 2 +``` + +ブロック関係の一覧表示: +```bash +# タスク1に関連するブロック関係を表示 +agkan task block list 1 +``` + +注意事項: +- 循環参照は自動的に検出され、エラーとなります +- ブロック関係はタスク削除時に自動的に削除されます(CASCADE DELETE) + +JSON出力フォーマット: +```bash +agkan task block list 2 --json +``` + +```json +{ + "task": { + "id": 2, + "title": "API implementation", + "status": "backlog" + }, + "blockedBy": [ + { + "id": 1, + "title": "Database design", + "status": "in_progress" + } + ], + "blocking": [ + { + "id": 3, + "title": "Frontend implementation", + "status": "backlog" + } + ] +} +``` + +### タスクの削除 + +タスクを削除: +```bash +agkan task delete 1 +``` + +### タグ管理 + +タグを作成: +```bash +agkan tag add "frontend" +``` + +タグ一覧を表示: +```bash +agkan tag list +``` + +タグを削除: +```bash +agkan tag delete "frontend" +``` + +タグ一覧のJSON出力フォーマット: +```bash +agkan tag list --json +``` + +```json +{ + "totalCount": 2, + "tags": [ + { + "id": 1, + "name": "frontend", + "taskCount": 3, + "created_at": "2026-02-15T00:00:00.000Z" + }, + { + "id": 2, + "name": "backend", + "taskCount": 1, + "created_at": "2026-02-15T00:00:00.000Z" + } + ] +} +``` + +### タスクへのタグ付け + +タスクにタグを付与: +```bash +agkan tag attach 1 "frontend" +``` + +または `task add --tag` でタスク作成と同時にタグを付与(`tag attach` を別途実行する必要がない): +```bash +agkan task add "ログイン画面の実装" --tag "frontend,urgent" +``` + +タスクからタグを削除: +```bash +agkan tag detach 1 "frontend" +``` + +タスクに付けられたタグを表示: +```bash +agkan tag show 1 +``` + +タグ表示のJSON出力フォーマット: +```bash +agkan tag show 1 --json +``` + +```json +{ + "task": { + "id": 1, + "title": "Implement login screen", + "status": "in_progress" + }, + "tags": [ + { + "id": 1, + "name": "frontend", + "created_at": "2026-02-15T00:00:00.000Z" + }, + { + "id": 3, + "name": "urgent", + "created_at": "2026-02-15T00:00:00.000Z" + } + ] +} +``` + +### メタデータの管理 + +メタデータを設定: +```bash +agkan task meta set 1 priority high +``` + +メタデータを取得: +```bash +agkan task meta get 1 priority +``` + +メタデータ一覧を表示: +```bash +agkan task meta list 1 +``` + +メタデータを削除: +```bash +agkan task meta delete 1 priority +``` + +#### 優先度 (priority) + +タスクの優先度は `priority` キーで管理します: + +| 値 | 意味 | +|-----|------| +| `critical` | 即時対応が必要。ブロッカーとなっている問題 | +| `high` | 優先して着手すべきタスク | +| `medium` | 通常の優先度(デフォルト) | +| `low` | 余裕があれば対応するタスク | + +### タスクのカウント + +全ステータスのタスク数を表示: +```bash +agkan task count +``` + +特定のステータスのタスク数を表示: +```bash +agkan task count --status in_progress +``` + +スクリプト用の出力(数値のみ): +```bash +agkan task count -s in_progress -q +``` + +全ステータスのJSON出力フォーマット: +```bash +agkan task count --json +``` + +```json +{ + "total": 10, + "counts": { + "backlog": 3, + "ready": 2, + "in_progress": 4, + "done": 1, + "closed": 0 + } +} +``` + +特定ステータスのJSON出力フォーマット: +```bash +agkan task count --status in_progress --json +``` + +```json +{ + "status": "in_progress", + "count": 4 +} +``` + +### カンバンボード (Web UI) + +ブラウザでローカルのカンバンボードビューアを起動: +```bash +agkan board +``` + +カスタムポートを指定: +```bash +agkan board -p 3000 +``` + +デフォルトでは `http://localhost:8080` でボードが提供されます。 + +#### ボードのClaude連携機能 + +ボードUIにはブラウザから直接Claudeを実行するための機能が組み込まれています: + +- **Runボタン**: タスクカードにある「Run」ボタンをクリックすると、そのタスクに対して `claude` を起動します。ボタン横のドロップダウンからプランモードで実行することもできます。 +- **Planボタン**: タスクを実行せずに計画のみを生成するプランモードで `claude` を起動します。 +- **ストリームモーダル**: Claude実行中はモーダルウィンドウにリアルタイムで出力が表示されます。「Stop」ボタンでプロセスを終了できます。 +- **実行中インジケーター**: Claudeプロセスが動作中の場合、ヘッダーにインジケーターが表示されます。 +- **実行ログタブ**: タスク詳細パネルの「Run Logs」タブに、過去のClaude実行履歴(タイムスタンプと全出力)が表示されます。 + +### Claudeプロセスの状態確認 + +現在実行中のClaudeプロセスを一覧表示します(ボードサーバーが起動している必要があります): +```bash +agkan ps +``` + +カスタムポートのボードサーバーに接続: +```bash +agkan ps --port 3000 +``` + +このコマンドはボードサーバーに問い合わせて、現在実行中のClaudeプロセスとそれに関連するタスクを表示します。 + +JSON出力フォーマット: +```bash +agkan ps --json +``` +```json +{ + "processes": [ + { + "taskId": 42, + "title": "機能Xの実装", + "command": "claude" + } + ] +} +``` + +### 設定確認 + +`.agkan.yml` の設定値(デフォルト適用後の解決済み値)を取得します: + +```bash +agkan config get # 全設定を表示 +agkan config get board.port # 特定キーを取得(ドット記法) +agkan config get --json # JSON出力 +``` + +出力例: +``` +✓ Resolved config + +path: /workspace/.agkan/data.db +board.port: 8080 +``` + +### ヘルプの表示 + +コマンド一覧: +```bash +agkan --help +``` + +タスクコマンドのヘルプ: +```bash +agkan task --help +``` + +個別コマンドのヘルプ: +```bash +agkan task add --help +``` + +## JSON出力フォーマット + +agkanは10のデータ取得・表示コマンドで、機械可読なJSON出力をサポートしています。`--json`フラグを追加することで、人間が読みやすいテキストの代わりに構造化されたデータを出力できます。 + +### 対応コマンド + +以下のコマンドがJSON出力をサポートしています: + +- `task add` - 新しいタスクを作成 +- `task list` - タスク一覧を表示(フィルタリング付き) +- `task get` - タスク詳細を取得 +- `task find` - キーワードでタスクを検索 +- `task count` - ステータス別のタスク数をカウント +- `task update-parent` - 親子関係を更新 +- `task block list` - ブロック関係を一覧表示 +- `task tag list` - 全タグをタスク数と共に一覧表示 +- `task tag show` - 特定のタスクのタグを表示 +- `task meta list` - タスクのメタデータ一覧を表示 +- `ps` - 現在実行中のClaudeプロセスを一覧表示 + +### 出力構造 + +すべてのJSONレスポンスは以下のパターンに従います: + +**成功レスポンス**には以下が含まれます: +- 操作固有のデータ(task、tasksの配列、counts など) +- 関連データ(parent、blockedBy、blocking、tags など) +- 書き込み操作の場合はオプションで`success: true`フィールド + +**エラーレスポンス**は以下のフォーマットに従います: +```json +{ + "success": false, + "error": { + "message": "エラーの説明" + } +} +``` + +### 一般的な使用例 + +**1. スクリプティングと自動化** +```bash +# CI/CDパイプライン用のタスク数を取得 +TASK_COUNT=$(agkan task count --status backlog --json | jq '.counts.backlog') + +# 処理用にタスクIDを抽出 +agkan task list --status ready --json | jq -r '.tasks[].id' +``` + +**2. 他ツールとの統合** +```bash +# タスクを外部システムにエクスポート +agkan task list --json | jq '.tasks' > tasks.json + +# ブロック関係を処理 +agkan task block list 1 --json | jq '.blockedBy[].title' +``` + +**3. 検証とテスト** +```bash +# タスク作成を検証 +RESULT=$(agkan task add "Test" --json) +echo $RESULT | jq -e '.success == true' && echo "Success" +``` + +## 使用例 + +### 親子関係を使った階層的なタスク管理 + +プロジェクトを親タスク、個別の作業を子タスクとして管理する例: + +```bash +# 親タスクを作成 +agkan task add "Webサイトのリニューアル" +# 出力: Task created with ID: 1 + +# 子タスクを作成 +agkan task add "デザインカンプ作成" --parent 1 +agkan task add "フロントエンド実装" --parent 1 +agkan task add "バックエンド実装" --parent 1 + +# ツリー形式で表示 +agkan task list --tree +# 出力: +# 1 [backlog] Webサイトのリニューアル +# ├─ 2 [backlog] デザインカンプ作成 +# ├─ 3 [backlog] フロントエンド実装 +# └─ 4 [backlog] バックエンド実装 + +# タスク詳細を表示(親情報を含む) +agkan task get 2 +# 出力: +# ID: 2 +# Title: デザインカンプ作成 +# Parent ID: 1 +# ... + +# 親を変更 +agkan task add "UI/UX改善" +# 出力: Task created with ID: 5 +agkan task update-parent 2 5 + +# 親を解除(孤立化) +agkan task update-parent 2 null +``` + +### ブロック関係を使った依存関係の管理 + +タスク間の依存関係を明示的に管理する例: + +```bash +# タスクを作成 +agkan task add "データベース設計" +# 出力: Task created with ID: 1 + +agkan task add "API実装" +# 出力: Task created with ID: 2 + +agkan task add "フロントエンド実装" +# 出力: Task created with ID: 3 + +# ブロック関係を設定(1がデータベース設計、2がAPI実装、3がフロントエンド実装) +# データベース設計がAPI実装をブロック +agkan task block add 1 2 + +# API実装がフロントエンド実装をブロック +agkan task block add 2 3 + +# ブロック関係を確認 +agkan task block list 1 +# 出力: +# Task 1 blocks: +# - Task 2 (API実装) +# Task 1 is blocked by: +# (none) + +agkan task block list 2 +# 出力: +# Task 2 blocks: +# - Task 3 (フロントエンド実装) +# Task 2 is blocked by: +# - Task 1 (データベース設計) + +# 循環参照を試みる(エラーになる) +agkan task block add 3 1 +# 出力: Error: Circular reference detected + +# ブロック関係を削除 +agkan task block remove 1 2 +``` + +### タグを使ったタスク管理 + +タスクにタグを付けて分類する例: + +```bash +# タグを作成 +agkan tag add "frontend" +agkan tag add "backend" +agkan tag add "urgent" + +# タスクを作成してタグを付与 +agkan task add "ログイン画面の実装" +# 出力: Task created with ID: 1 + +agkan tag attach 1 "frontend" +agkan tag attach 1 "urgent" + +agkan task add "API開発" +# 出力: Task created with ID: 2 + +agkan tag attach 2 "backend" + +# --tag を使えば同じコマンドでタグを付与できる +agkan task add "決済フローのバグ修正" --tag "backend,urgent" +# 出力: Task created with ID: 3 + +# タグでフィルタリング +agkan task list --tag "frontend" +# 出力: +# 1 [backlog] ログイン画面の実装 (tags: frontend, urgent) + +# タスクのタグを確認 +agkan tag show 1 +# 出力: +# Tags for task 1: +# - frontend +# - urgent + +# タグを削除 +agkan tag detach 1 "urgent" + +# タグ自体を削除(関連するすべてのタスクから削除される) +agkan tag delete "urgent" +``` diff --git a/documentation/cli-reference.md b/documentation/cli-reference.md new file mode 100644 index 00000000..a577157e --- /dev/null +++ b/documentation/cli-reference.md @@ -0,0 +1,819 @@ +# CLI Reference + +Full command reference for agkan, including every subcommand, its options, and JSON output formats. + +## Table of Contents + +- [Usage](#usage) + - [Initialize a Project](#initialize-a-project) + - [Create Tasks](#create-tasks) + - [List Tasks](#list-tasks) + - [Search Tasks](#search-tasks) + - [Get Task Details](#get-task-details) + - [Update Tasks](#update-tasks) + - [Manage Parent-Child Relationships](#manage-parent-child-relationships) + - [Manage Blocking Relationships](#manage-blocking-relationships) + - [Delete Tasks](#delete-tasks) + - [Manage Tags](#manage-tags) + - [Attach Tags to Tasks](#attach-tags-to-tasks) + - [Manage Metadata](#manage-metadata) + - [Count Tasks](#count-tasks) + - [Kanban Board (Web UI)](#kanban-board-web-ui) + - [Claude Process Status](#claude-process-status) + - [Config](#config) + - [Display Help](#display-help) +- [JSON Output Format](#json-output-format) + - [Supported Commands](#supported-commands) + - [Output Structure](#output-structure) + - [Common Use Cases](#common-use-cases) +- [Usage Examples](#usage-examples) + - [Hierarchical Task Management with Parent-Child Relationships](#hierarchical-task-management-with-parent-child-relationships) + - [Managing Dependencies with Blocking Relationships](#managing-dependencies-with-blocking-relationships) + - [Task Management with Tags](#task-management-with-tags) + +## Usage + +### Initialize a Project + +Run `agkan init` in your project directory to set up agkan: + +```bash +agkan init +``` + +This creates: +- `.agkan.yml` — configuration file +- `.agkan/` — data directory + +`agkan init` also installs a SessionStart hook into `.claude/settings.local.json` +so that Claude Code automatically loads a minimal agkan usage brief at the +start of every session. The hook calls `agkan context --hook`. This step is +idempotent and merges into existing settings without touching unrelated keys. +If you are not using Claude Code, you can safely ignore the generated file. + +### Create Tasks + +Basic task creation: +```bash +agkan task add "Task title" "Task description" +``` + +Create with options: +```bash +agkan task add "Implement login feature" "Implement user authentication system" \ + --status ready \ + --author "developer-name" +``` + +Create with parent task: +```bash +agkan task add "Subtask" "Detailed work item" --parent 1 +``` + +Create from Markdown file: +```bash +agkan task add "Design review" --file ./design-doc.md --status backlog +``` + +Create with tags (comma-separated names or IDs, attached in the same command): +```bash +agkan task add "Implement login feature" --tag "frontend,urgent" +``` + +JSON output format: +```bash +agkan task add "Fix bug in login" --json +``` + +```json +{ + "success": true, + "task": { + "id": 1, + "title": "Fix bug in login", + "status": "backlog", + "body": null, + "author": null, + "parent_id": null, + "created_at": "2026-02-15T00:00:00.000Z", + "updated_at": "2026-02-15T00:00:00.000Z" + }, + "parent": null, + "blockedBy": [], + "blocking": [] +} +``` + +### List Tasks + +Display all tasks: +```bash +agkan task list +``` + +Display in tree format (including parent-child relationships): +```bash +agkan task list --tree +``` + +Display root tasks only (tasks without parents): +```bash +agkan task list --root-only +``` + +Filter by status: +```bash +agkan task list --status in_progress +``` + +Filter by author: +```bash +agkan task list --author "developer-name" +``` + +Combined filters: +```bash +agkan task list --status ready --author "developer-name" +``` + +Filter by tag: +```bash +agkan task list --tag "frontend" +``` + +JSON output format: +```bash +agkan task list --json +``` + +```json +{ + "tasks": [ + { + "id": 1, + "title": "Implement login feature", + "status": "in_progress", + "body": "Implement user authentication system", + "author": "developer-name", + "parent_id": null, + "created_at": "2026-02-15T00:00:00.000Z", + "updated_at": "2026-02-15T00:00:00.000Z" + }, + { + "id": 2, + "title": "Design review", + "status": "backlog", + "body": null, + "author": null, + "parent_id": null, + "created_at": "2026-02-15T00:00:00.000Z", + "updated_at": "2026-02-15T00:00:00.000Z" + } + ] +} +``` + +### Search Tasks + +Search by keyword (in title and body): +```bash +agkan task find "search keyword" +``` + +Include completed tasks in search: +```bash +agkan task find "search keyword" --all +``` + +Note: By default, `done` and `closed` tasks are excluded from search results. + +JSON output format: +```bash +agkan task find "login" --json +``` + +```json +{ + "tasks": [ + { + "id": 1, + "title": "Implement login feature", + "status": "in_progress", + "body": "Implement user authentication system", + "author": "developer-name", + "parent_id": null, + "created_at": "2026-02-15T00:00:00.000Z", + "updated_at": "2026-02-15T00:00:00.000Z" + } + ] +} +``` + +### Get Task Details + +```bash +agkan task get 1 +``` + +JSON output format: +```bash +agkan task get 1 --json +``` + +```json +{ + "task": { + "id": 1, + "title": "Implement login feature", + "status": "in_progress", + "body": "Implement user authentication system", + "author": "developer-name", + "parent_id": null, + "created_at": "2026-02-15T00:00:00.000Z", + "updated_at": "2026-02-15T00:00:00.000Z" + } +} +``` + +### Update Tasks + +Change status: +```bash +agkan task update 1 status done +``` + +Change title: +```bash +agkan task update 1 title "New title" +``` + +Change body: +```bash +agkan task update 1 body "New description" +``` + +Change author: +```bash +agkan task update 1 author "new-author" +``` + +### Manage Parent-Child Relationships + +Update parent task: +```bash +# Set parent of task 2 to task 1 +agkan task update-parent 2 1 + +# Remove parent (orphan task 2) +agkan task update-parent 2 null +``` + +Notes: +- Deleting a parent task automatically removes the parent reference from child tasks (orphaning them) +- Circular references are automatically detected and prevented + +JSON output format: +```bash +agkan task update-parent 2 1 --json +``` + +```json +{ + "success": true, + "task": { + "id": 2, + "title": "Child Task", + "status": "backlog", + "body": null, + "author": null, + "parent_id": 1, + "created_at": "2026-02-15T00:00:00.000Z", + "updated_at": "2026-02-15T00:00:00.000Z" + }, + "parent": { + "id": 1, + "title": "Parent Task", + "status": "backlog", + "body": null, + "author": null, + "parent_id": null, + "created_at": "2026-02-15T00:00:00.000Z", + "updated_at": "2026-02-15T00:00:00.000Z" + } +} +``` + +### Manage Blocking Relationships + +Add blocking relationship (task 1 blocks task 2): +```bash +agkan task block add 1 2 +``` + +Remove blocking relationship: +```bash +agkan task block remove 1 2 +``` + +List blocking relationships: +```bash +# Show blocking relationships for task 1 +agkan task block list 1 +``` + +Notes: +- Circular references are automatically detected and prevented +- Blocking relationships are automatically deleted when a task is deleted (CASCADE DELETE) + +JSON output format: +```bash +agkan task block list 2 --json +``` + +```json +{ + "task": { + "id": 2, + "title": "API implementation", + "status": "backlog" + }, + "blockedBy": [ + { + "id": 1, + "title": "Database design", + "status": "in_progress" + } + ], + "blocking": [ + { + "id": 3, + "title": "Frontend implementation", + "status": "backlog" + } + ] +} +``` + +### Delete Tasks + +Delete a task: +```bash +agkan task delete 1 +``` + +### Manage Tags + +Create a tag: +```bash +agkan tag add "frontend" +``` + +List all tags: +```bash +agkan tag list +``` + +Delete a tag: +```bash +agkan tag delete "frontend" +``` + +JSON output format for tag list: +```bash +agkan tag list --json +``` + +```json +{ + "totalCount": 2, + "tags": [ + { + "id": 1, + "name": "frontend", + "taskCount": 3, + "created_at": "2026-02-15T00:00:00.000Z" + }, + { + "id": 2, + "name": "backend", + "taskCount": 1, + "created_at": "2026-02-15T00:00:00.000Z" + } + ] +} +``` + +### Attach Tags to Tasks + +Attach a tag to a task: +```bash +agkan tag attach 1 "frontend" +``` + +Or attach tags at creation time with `task add --tag`, instead of a separate `tag attach` call: +```bash +agkan task add "Implement login screen" --tag "frontend,urgent" +``` + +Remove a tag from a task: +```bash +agkan tag detach 1 "frontend" +``` + +Display tags on a task: +```bash +agkan tag show 1 +``` + +JSON output format for tag show: +```bash +agkan tag show 1 --json +``` + +```json +{ + "task": { + "id": 1, + "title": "Implement login screen", + "status": "in_progress" + }, + "tags": [ + { + "id": 1, + "name": "frontend", + "created_at": "2026-02-15T00:00:00.000Z" + }, + { + "id": 3, + "name": "urgent", + "created_at": "2026-02-15T00:00:00.000Z" + } + ] +} +``` + +### Manage Metadata + +Set metadata: +```bash +agkan task meta set 1 priority high +``` + +Get metadata: +```bash +agkan task meta get 1 priority +``` + +List all metadata: +```bash +agkan task meta list 1 +``` + +Delete metadata: +```bash +agkan task meta delete 1 priority +``` + +#### Priority (priority) + +Task priority is managed with the `priority` key: + +| Value | Meaning | +|-------|---------| +| `critical` | Requires immediate action. A blocking issue. | +| `high` | Should be addressed with priority | +| `medium` | Normal priority (default) | +| `low` | Address when time permits | + +### Count Tasks + +Display task count for all statuses: +```bash +agkan task count +``` + +Display task count for a specific status: +```bash +agkan task count --status in_progress +``` + +Script-friendly output (numbers only): +```bash +agkan task count -s in_progress -q +``` + +JSON output format for all statuses: +```bash +agkan task count --json +``` + +```json +{ + "total": 10, + "counts": { + "backlog": 3, + "ready": 2, + "in_progress": 4, + "done": 1, + "closed": 0 + } +} +``` + +JSON output format for specific status: +```bash +agkan task count --status in_progress --json +``` + +```json +{ + "status": "in_progress", + "count": 4 +} +``` + +### Kanban Board (Web UI) + +Start a local Kanban board viewer in your browser: +```bash +agkan board +``` + +Specify a custom port: +```bash +agkan board -p 3000 +``` + +The board is served at `http://localhost:8080` by default. + +#### Claude Integration in the Board + +The board UI includes built-in Claude integration for running tasks directly from the browser: + +- **Run button**: Each task card has a "Run" button that launches `claude` for that task. A dropdown arrow next to the button also allows running in plan mode. +- **Plan button**: Runs `claude` in plan mode to generate a plan for the task without executing. +- **Stream modal**: When Claude is running, a modal window displays the live output stream in real time. A "Stop" button allows terminating the process. +- **Running indicator**: A header indicator shows when any Claude process is currently active. +- **Run Logs tab**: The task detail panel includes a "Run Logs" tab that shows the history of all past Claude executions for that task, with timestamps and full output. + +### Claude Process Status + +List currently executing Claude processes (requires the board server to be running): +```bash +agkan ps +``` + +Connect to a board server on a custom port: +```bash +agkan ps --port 3000 +``` + +This command queries the board server to show which Claude processes are currently running and which tasks they are associated with. + +JSON output format: +```bash +agkan ps --json +``` +```json +{ + "processes": [ + { + "taskId": 42, + "title": "Implement feature X", + "command": "claude" + } + ] +} +``` + +### Config + +Get resolved configuration values from `.agkan.yml` (defaults applied): + +```bash +agkan config get # Show full resolved config +agkan config get board.port # Show specific key (dot notation) +agkan config get --json # JSON output +``` + +Example output: +``` +✓ Resolved config + +path: /workspace/.agkan/data.db +board.port: 8080 +``` + +### Display Help + +Show command list: +```bash +agkan --help +``` + +Show task command help: +```bash +agkan task --help +``` + +Show help for specific command: +```bash +agkan task add --help +``` + +## JSON Output Format + +agkan supports machine-readable JSON output for 10 data retrieval and display commands. Add the `--json` flag to output structured data instead of human-readable text. + +### Supported Commands + +The following commands support JSON output: + +- `task add` - Create a new task +- `task list` - List tasks (with filtering) +- `task get` - Get task details +- `task find` - Search tasks by keyword +- `task count` - Count tasks by status +- `task update-parent` - Update parent-child relationship +- `task block list` - List blocking relationships +- `task tag list` - List all tags with task counts +- `task tag show` - Show tags for a specific task +- `task meta list` - List all metadata for a task +- `ps` - List currently executing Claude processes + +### Output Structure + +All JSON responses follow these patterns: + +**Success responses** include: +- Operation-specific data (task, tasks array, counts, etc.) +- Related data (parent, blockedBy, blocking, tags, etc.) +- Optional `success: true` field for write operations + +**Error responses** follow the format: +```json +{ + "success": false, + "error": { + "message": "Error description" + } +} +``` + +### Common Use Cases + +**1. Scripting and Automation** +```bash +# Get task count for CI/CD pipeline +TASK_COUNT=$(agkan task count --status backlog --json | jq '.counts.backlog') + +# Extract task IDs for processing +agkan task list --status ready --json | jq -r '.tasks[].id' +``` + +**2. Integration with Other Tools** +```bash +# Export tasks to external system +agkan task list --json | jq '.tasks' > tasks.json + +# Process blocking relationships +agkan task block list 1 --json | jq '.blockedBy[].title' +``` + +**3. Validation and Testing** +```bash +# Verify task creation +RESULT=$(agkan task add "Test" --json) +echo $RESULT | jq -e '.success == true' && echo "Success" +``` + +## Usage Examples + +### Hierarchical Task Management with Parent-Child Relationships + +Example of managing a project as a parent task with individual work items as children: + +```bash +# Create parent task +agkan task add "Website redesign" +# Output: Task created with ID: 1 + +# Create child tasks +agkan task add "Create design mockup" --parent 1 +agkan task add "Implement frontend" --parent 1 +agkan task add "Implement backend" --parent 1 + +# Display in tree format +agkan task list --tree +# Output: +# 1 [backlog] Website redesign +# ├─ 2 [backlog] Create design mockup +# ├─ 3 [backlog] Implement frontend +# └─ 4 [backlog] Implement backend + +# Display task details (including parent information) +agkan task get 2 +# Output: +# ID: 2 +# Title: Create design mockup +# Parent ID: 1 +# ... + +# Change parent +agkan task add "UI/UX improvements" +# Output: Task created with ID: 5 +agkan task update-parent 2 5 + +# Remove parent (orphan task) +agkan task update-parent 2 null +``` + +### Managing Dependencies with Blocking Relationships + +Example of explicitly managing task dependencies: + +```bash +# Create tasks +agkan task add "Database design" +# Output: Task created with ID: 1 + +agkan task add "API implementation" +# Output: Task created with ID: 2 + +agkan task add "Frontend implementation" +# Output: Task created with ID: 3 + +# Set blocking relationships (1 blocks 2, 2 blocks 3) +# Database design blocks API implementation +agkan task block add 1 2 + +# API implementation blocks Frontend implementation +agkan task block add 2 3 + +# Verify blocking relationships +agkan task block list 1 +# Output: +# Task 1 blocks: +# - Task 2 (API implementation) +# Task 1 is blocked by: +# (none) + +agkan task block list 2 +# Output: +# Task 2 blocks: +# - Task 3 (Frontend implementation) +# Task 2 is blocked by: +# - Task 1 (Database design) + +# Attempt circular reference (error) +agkan task block add 3 1 +# Output: Error: Circular reference detected + +# Remove blocking relationship +agkan task block remove 1 2 +``` + +### Task Management with Tags + +Example of classifying tasks with tags: + +```bash +# Create tags +agkan tag add "frontend" +agkan tag add "backend" +agkan tag add "urgent" + +# Create tasks and attach tags +agkan task add "Implement login screen" +# Output: Task created with ID: 1 + +agkan tag attach 1 "frontend" +agkan tag attach 1 "urgent" + +agkan task add "API development" +# Output: Task created with ID: 2 + +agkan tag attach 2 "backend" + +# Or attach tags in the same command with --tag +agkan task add "Bug fix in payment flow" --tag "backend,urgent" +# Output: Task created with ID: 3 + +# Filter by tag +agkan task list --tag "frontend" +# Output: +# 1 [backlog] Implement login screen (tags: frontend, urgent) + +# Display task tags +agkan tag show 1 +# Output: +# Tags for task 1: +# - frontend +# - urgent + +# Remove a tag +agkan tag detach 1 "urgent" + +# Delete a tag (removes from all associated tasks) +agkan tag delete "urgent" +``` From f16c14a4f53835485e7a8e1a048c9dc1d835794a Mon Sep 17 00:00:00 2001 From: GENDOSU Date: Fri, 10 Jul 2026 14:43:16 +0000 Subject: [PATCH 2/6] docs: add documentation/configuration.md and .ja.md Migrate the Configuration chapter from README.md/README.ja.md into dedicated documentation files, and fix the Board Settings default port from 3000 to 8080 to match DEFAULT_BOARD_PORT in src/cli/utils/constants.ts. --- documentation/configuration.ja.md | 266 ++++++++++++++++++++++++++++ documentation/configuration.md | 279 ++++++++++++++++++++++++++++++ 2 files changed, 545 insertions(+) create mode 100644 documentation/configuration.ja.md create mode 100644 documentation/configuration.md diff --git a/documentation/configuration.ja.md b/documentation/configuration.ja.md new file mode 100644 index 00000000..bc9d910e --- /dev/null +++ b/documentation/configuration.ja.md @@ -0,0 +1,266 @@ +# 設定 + +`.agkan.yml` の全フィールド・データベースパスの解決順序・テストモードの挙動・プロジェクトごとの管理方法を網羅した設定リファレンスです。 + +## 目次 + +- [データベースの保存場所](#データベースの保存場所) + - [設定ファイル: `.agkan.yml`](#設定ファイル-agkanyml) + - [パスの指定方法](#パスの指定方法) + - [環境変数による設定](#環境変数による設定) + - [デフォルトの動作](#デフォルトの動作) + - [プロジェクトごとの管理](#プロジェクトごとの管理) +- [ボード設定](#ボード設定) +- [モデル設定](#モデル設定) +- [パーミッションモード設定](#パーミッションモード設定) + +## データベースの保存場所 + +agkanは、データベースの保存場所を設定ファイルでカスタマイズできます。 + +### 設定ファイル: `.agkan.yml` + +プロジェクトのルートディレクトリに`.agkan.yml`ファイルを作成することで、データベースの保存場所を指定できます。 + +**設定例:** + +```yaml +# データベースファイルのパス +path: ./.agkan/data.db +``` + +### パスの指定方法 + +- **相対パス**: カレントディレクトリからの相対パスとして解決されます + ```yaml + path: ./data/kanban.db + path: ./.agkan/data.db + ``` + +- **絶対パス**: そのままのパスが使用されます + ```yaml + path: /home/user/.config/agkan/data.db + ``` + +### 環境変数による設定 + +agkanは `AGENT_KANBAN_DB_PATH` 環境変数によるデータベースの場所指定をサポートしています。CI/CD環境や複数環境の管理に特に有用です。 + +**環境変数の設定例:** + +```bash +# カスタムデータベースパスを使用 +export AGENT_KANBAN_DB_PATH=/path/to/your/database.db +agkan task list + +# 絶対パスを使用 +export AGENT_KANBAN_DB_PATH=/home/user/.config/agkan/data.db + +# 相対パスを使用 +export AGENT_KANBAN_DB_PATH=./custom/location/data.db +``` + +**優先順位:** + +データベースパスは以下の優先順位で解決されます: + +**通常モード (`NODE_ENV` が `test` でない場合):** +1. **環境変数**(最高優先): `AGENT_KANBAN_DB_PATH` +2. **設定ファイル**(フォールバック): `.agkan.yml` の `path` フィールド +3. **デフォルトパス**(最低優先): `.agkan/data.db` + +**テストモード (`NODE_ENV=test` の場合):** +1. **環境変数**(最高優先): `AGENT_KANBAN_DB_PATH` +2. **設定ファイル**(フォールバック): `.agkan-test.yml` の `path` フィールド +3. **デフォルトパス**(最低優先): `.agkan-test/data.db` + +**テストモードについて:** + +テストモード(`NODE_ENV=test`)では、テストデータと本番データを自動的に分離します: + +- 別の設定ファイルを使用: `.agkan.yml` の代わりに `.agkan-test.yml` +- 別のデフォルトディレクトリを使用: `.agkan/` の代わりに `.agkan-test/` +- テストモードでも環境変数が最高優先になります + +**使用例:** + +```bash +# CI/CDパイプライン(一時DBを使用) +export AGENT_KANBAN_DB_PATH=/tmp/ci-test-db.db +agkan task list + +# 複数環境の管理 +export AGENT_KANBAN_DB_PATH=./dev/data.db # 開発環境 +export AGENT_KANBAN_DB_PATH=./staging/data.db # ステージング環境 + +# テストの実行 +NODE_ENV=test pnpm test +# デフォルトで .agkan-test/data.db を使用 + +# カスタムテストDBで実行 +NODE_ENV=test AGENT_KANBAN_DB_PATH=/tmp/test.db pnpm test +``` + +### デフォルトの動作 + +`.agkan.yml`ファイルが存在せず、環境変数も設定されていない場合、データベースは以下の場所に作成されます: + +``` +<カレントディレクトリ>/.agkan/data.db +``` + +テストモード(`NODE_ENV=test`)の場合のデフォルト: + +``` +<カレントディレクトリ>/.agkan-test/data.db +``` + +### プロジェクトごとの管理 + +プロジェクトごとに異なるタスク管理を行いたい場合は、各プロジェクトのルートに`.agkan.yml`を配置してください: + +```bash +# プロジェクトA +cd /path/to/projectA +cat > .agkan.yml << EOF +path: ./.agkan/data.db +EOF + +# プロジェクトB +cd /path/to/projectB +cat > .agkan.yml << EOF +path: ./.agkan/data.db +EOF +``` + +これにより、各プロジェクトで独立したタスク管理が可能になります。 + +## ボード設定 + +`.agkan.yml` の `board` セクションでは、`agkan board` コマンドの動作をカスタマイズできます。 + +### 利用可能なフィールド + +| フィールド | 型 | デフォルト値 | 説明 | +|----------|-----|------------|------| +| `board.port` | number | `8080` | ボードWebサーバーのポート番号 | +| `board.title` | string | `"agkan Board"` | ボードUIに表示されるタイトル | + +### 設定例 + +```yaml +# データベースファイルのパス +path: ./.agkan/data.db + +# ボード設定 +board: + port: 8080 + title: "マイプロジェクトボード" +``` + +### フィールドの詳細 + +- **`board.port`**: ボードWebサーバーがリッスンするTCPポートを指定します。デフォルトポート `8080` が既に使用中の場合に有用です。 + ```yaml + board: + port: 8080 + ``` + +- **`board.title`**: ボードUIに表示されるタイトルを設定します。複数のプロジェクトを管理する際に、ボードを区別するのに役立ちます。 + ```yaml + board: + title: "マイプロジェクトボード" + ``` + +## モデル設定 + +`.agkan.yml` の `models` セクションでは、ボード経由でplanningおよびrunコマンドを実行する際に使用するClaudeモデルとeffortレベルを指定できます。 + +### 利用可能なフィールド + +| フィールド | 型 | デフォルト値 | 説明 | +|----------|-----|------------|------| +| `models.planning.model` | string | (Claude CLIのデフォルト) | planningコマンド実行時に使用するモデル | +| `models.planning.effort` | string | (Claude CLIのデフォルト) | planningコマンドのeffortレベル(`low`, `medium`, `high`, `xhigh`, `max`) | +| `models.run.model` | string | (Claude CLIのデフォルト) | run/prコマンド実行時に使用するモデル | +| `models.run.effort` | string | (Claude CLIのデフォルト) | run/prコマンドのeffortレベル(`low`, `medium`, `high`, `xhigh`, `max`) | + +フルモデル名とClaude CLIのエイリアスの両方が使用できます。`model` と `effort` はいずれも省略可能です。 + +### 設定例 + +```yaml +# データベースファイルのパス +path: ./.agkan/data.db + +# モデル設定 +models: + planning: + model: claude-opus-4-7 + effort: high + run: + model: claude-sonnet-4-6 + effort: low +``` + +### エイリアスの使用 + +フルモデル名の代わりに短いエイリアスを使用できます: + +```yaml +models: + planning: + model: opus + effort: high + run: + model: sonnet +``` + +使用可能なエイリアス: `opus`、`sonnet`、`haiku`(Claude CLIが解決します) + +### フィールドの詳細 + +- **`models.planning`**: ボードがplanningタスクを実行する際に使用するClaudeモデルとeffortレベルを指定します。`opus` や `claude-opus-4-7` など高性能なモデルと高いeffortレベルの使用を推奨します。 + ```yaml + models: + planning: + model: opus + effort: high + ``` + +- **`models.run`**: ボードがrunまたはprコマンドを実行する際に使用するClaudeモデルとeffortレベルを指定します。`pr` コマンドもこの値を使用します。 + ```yaml + models: + run: + model: sonnet + effort: low + ``` + +## パーミッションモード設定 + +`.agkan.yml` の `permissionMode` フィールドで、ボードからタスクを実行する際のClaude CLIのパーミッションチェック方法を制御できます。 + +### 利用可能な値 + +| 値 | Claude CLI フラグ | 説明 | +|-------|----------------|-------------| +| (未設定) | `--permission-mode auto` | デフォルト。Claudeがautoパーミッションモードを使用 | +| `auto` | `--permission-mode auto` | Claudeがautoパーミッションモードを使用 | +| `bypassPermissions` | `--permission-mode bypassPermissions` | すべてのパーミッションチェックをバイパス | +| `acceptEdits` | `--permission-mode acceptEdits` | ファイル編集を自動的に承認 | +| `dontAsk` | `--permission-mode dontAsk` | パーミッションを確認しない | +| `plan` | `--permission-mode plan` | プランのみモード | +| `default` | `--permission-mode default` | Claudeのデフォルトパーミッションモード | +| `skipPermissions` | `--dangerously-skip-permissions` | レガシーフラグ(すべてのチェックをバイパスする旧来の動作) | + +### 設定例 + +```yaml +# autoパーミッションモードを使用(デフォルト) +permissionMode: auto + +# レガシーの --dangerously-skip-permissions フラグを使用 +permissionMode: skipPermissions +``` + +> **破壊的変更**: この機能導入以前は常に `--dangerously-skip-permissions` が渡されていました。新しいデフォルトは `--permission-mode auto` です。従来の動作を維持するには `.agkan.yml` に `permissionMode: skipPermissions` を設定してください。 diff --git a/documentation/configuration.md b/documentation/configuration.md new file mode 100644 index 00000000..77054b4b --- /dev/null +++ b/documentation/configuration.md @@ -0,0 +1,279 @@ +# Configuration + +Full configuration reference for agkan, covering `.agkan.yml` fields, database path resolution, test mode behavior, and per-project setup. + +## Table of Contents + +- [Database Storage Location](#database-storage-location) + - [Configuration File: `.agkan.yml`](#configuration-file-agkanyml) + - [Path Specification](#path-specification) + - [Environment Variable Configuration](#environment-variable-configuration) + - [Default Behavior](#default-behavior) + - [Per-Project Management](#per-project-management) +- [Board Settings](#board-settings) +- [Models Settings](#models-settings) +- [Permission Mode Settings](#permission-mode-settings) + +## Database Storage Location + +agkan allows customization of the database storage location via a configuration file. + +### Configuration File: `.agkan.yml` + +Create a `.agkan.yml` file in your project root directory to specify the database storage location. + +**Configuration Example:** + +```yaml +# Path to database file +path: ./.agkan/data.db +``` + +### Path Specification + +- **Relative Path**: Resolved relative to the current directory + ```yaml + path: ./data/kanban.db + path: ./.agkan/data.db + ``` + +- **Absolute Path**: Used as-is + ```yaml + path: /home/user/.config/akan/data.db + ``` + +### Environment Variable Configuration + +agkan supports the `AGENT_KANBAN_DB_PATH` environment variable for specifying the database location. This is particularly useful in CI/CD environments and for managing multiple environments. + +**Setting the Environment Variable:** + +```bash +# Use a custom database path +export AGENT_KANBAN_DB_PATH=/path/to/your/database.db +agkan task list + +# Use absolute path +export AGENT_KANBAN_DB_PATH=/home/user/.config/akan/data.db + +# Use relative path +export AGENT_KANBAN_DB_PATH=./custom/location/data.db +``` + +**Priority Order:** + +The database path is resolved in the following priority order: + +**Normal Mode (when `NODE_ENV` is not `test`):** +1. **Environment Variable** (highest priority): `AGENT_KANBAN_DB_PATH` +2. **Configuration File** (fallback): `path` field in `.agkan.yml` +3. **Default Path** (lowest priority): `.agkan/data.db` + +**Test Mode (when `NODE_ENV=test`):** +1. **Environment Variable** (highest priority): `AGENT_KANBAN_DB_PATH` +2. **Configuration File** (fallback): `path` field in `.agkan-test.yml` +3. **Default Path** (lowest priority): `.agkan-test/data.db` + +**Test Mode Explanation:** + +Test mode (`NODE_ENV=test`) automatically isolates test data from production data: + +- Uses separate configuration file: `.agkan-test.yml` instead of `.agkan.yml` +- Uses separate default directory: `.agkan-test/` instead of `.agkan/` +- Environment variable still takes highest priority in test mode +- Prevents accidental mixing of test and production data + +**Use Cases:** + +1. **CI/CD Pipeline:** + ```bash + # Use temporary database for CI tests + export AGENT_KANBAN_DB_PATH=/tmp/ci-test-db.db + agkan task list + ``` + +2. **Multiple Environments:** + ```bash + # Development environment + export AGENT_KANBAN_DB_PATH=./dev/data.db + + # Staging environment + export AGENT_KANBAN_DB_PATH=./staging/data.db + + # Production environment + export AGENT_KANBAN_DB_PATH=./prod/data.db + ``` + +3. **Testing:** + ```bash + # Automated tests with isolated database + NODE_ENV=test pnpm test + # Uses .agkan-test/data.db by default + + # Override with custom test database + NODE_ENV=test AGENT_KANBAN_DB_PATH=/tmp/test.db pnpm test + ``` + +### Default Behavior + +If no `.agkan.yml` file exists and no environment variable is set, the database is created in: + +``` +/.agkan/data.db +``` + +In test mode (`NODE_ENV=test`), the default location is: + +``` +/.agkan-test/data.db +``` + +### Per-Project Management + +To manage separate tasks for different projects, place `.agkan.yml` in each project root: + +```bash +# Project A +cd /path/to/projectA +cat > .agkan.yml << EOF +path: ./.agkan/data.db +EOF + +# Project B +cd /path/to/projectB +cat > .agkan.yml << EOF +path: ./.agkan/data.db +EOF +``` + +This enables independent task management for each project. + +## Board Settings + +The `board` section in `.agkan.yml` allows you to customize the behavior of the `agkan board` command. + +### Available Fields + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `board.port` | number | `8080` | Port number for the board web server | +| `board.title` | string | `"agkan Board"` | Title displayed in the board UI | + +### Configuration Example + +```yaml +# Path to database file +path: ./.agkan/data.db + +# Board settings +board: + port: 8080 + title: "My Project Board" +``` + +### Field Details + +- **`board.port`**: Specifies the TCP port on which the board web server listens. Useful when the default port `8080` is already in use. + ```yaml + board: + port: 8080 + ``` + +- **`board.title`**: Sets the title shown in the board UI. Helps distinguish boards when managing multiple projects. + ```yaml + board: + title: "My Project Board" + ``` + +## Models Settings + +The `models` section in `.agkan.yml` allows you to specify the Claude model and effort level used when executing planning and run commands via the board. + +### Available Fields + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `models.planning.model` | string | (Claude CLI default) | Model used for planning command execution | +| `models.planning.effort` | string | (Claude CLI default) | Effort level for planning command (`low`, `medium`, `high`, `xhigh`, `max`) | +| `models.run.model` | string | (Claude CLI default) | Model used for run/pr command execution | +| `models.run.effort` | string | (Claude CLI default) | Effort level for run/pr command (`low`, `medium`, `high`, `xhigh`, `max`) | + +Both full model names and Claude CLI aliases are supported. Both `model` and `effort` are optional within each entry. + +### Configuration Example + +```yaml +# Database path +path: ./.agkan/data.db + +# Model settings +models: + planning: + model: claude-opus-4-7 + effort: high + run: + model: claude-sonnet-4-6 + effort: low +``` + +### Using Aliases + +You can use short aliases instead of full model names: + +```yaml +models: + planning: + model: opus + effort: high + run: + model: sonnet +``` + +Supported aliases: `opus`, `sonnet`, `haiku` (resolved by the Claude CLI) + +### Field Details + +- **`models.planning`**: Specifies the Claude model and effort level used when the board executes planning tasks. Recommended to use a high-capability model and effort level such as `opus` with `high`. + ```yaml + models: + planning: + model: opus + effort: high + ``` + +- **`models.run`**: Specifies the Claude model and effort level used when the board executes run or pr commands. The `pr` command also uses this value. + ```yaml + models: + run: + model: sonnet + effort: low + ``` + +## Permission Mode Settings + +The `permissionMode` field in `.agkan.yml` controls how Claude CLI permission checks are handled when executing tasks from the board. + +### Available Values + +| Value | Claude CLI flag | Description | +|-------|----------------|-------------| +| (not set) | `--permission-mode auto` | Default. Claude uses auto permission mode | +| `auto` | `--permission-mode auto` | Claude uses auto permission mode | +| `bypassPermissions` | `--permission-mode bypassPermissions` | Bypass all permission checks | +| `acceptEdits` | `--permission-mode acceptEdits` | Automatically accept file edits | +| `dontAsk` | `--permission-mode dontAsk` | Do not ask for permissions | +| `plan` | `--permission-mode plan` | Plan-only mode | +| `default` | `--permission-mode default` | Claude default permission mode | +| `skipPermissions` | `--dangerously-skip-permissions` | Legacy flag (same as bypassing all checks) | + +### Configuration Example + +```yaml +# Use auto permission mode (default) +permissionMode: auto + +# Use legacy --dangerously-skip-permissions flag +permissionMode: skipPermissions +``` + +> **Breaking Change**: Prior to this feature, `--dangerously-skip-permissions` was always passed. The new default is `--permission-mode auto`. To restore the previous behavior, set `permissionMode: skipPermissions` in your `.agkan.yml`. From a2c8b3517834c8ebf990fb26c50a258a84984e10 Mon Sep 17 00:00:00 2001 From: GENDOSU Date: Fri, 10 Jul 2026 14:53:49 +0000 Subject: [PATCH 3/6] docs: add Kanban board screenshot for README hero --- docs/assets/readme-board.png | Bin 0 -> 77086 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/assets/readme-board.png diff --git a/docs/assets/readme-board.png b/docs/assets/readme-board.png new file mode 100644 index 0000000000000000000000000000000000000000..834099a5a6781b4cc7e10fb7ec2f290b0c7af899 GIT binary patch literal 77086 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 literal 0 HcmV?d00001 From a4b52c76b43ed3221d665e4c20d0ed83b35eaf6a Mon Sep 17 00:00:00 2001 From: GENDOSU Date: Fri, 10 Jul 2026 15:04:45 +0000 Subject: [PATCH 4/6] docs: rewrite README.md/README.ja.md to ergonomic structure Restructure both READMEs into Hero/Features/Quick Start/Command Reference/Claude Code Integration/Configuration/Task Statuses/ Documentation/License, cutting ~1150 lines down to ~190 by moving detailed CLI and configuration reference content into documentation/cli-reference.md and documentation/configuration.md. Move the Technology Stack section into documentation/development.md and documentation/development.ja.md, and drop the Planned Features chapter, which referenced a nonexistent doc and an unimplemented command. --- README.ja.md | 1197 ++++--------------------------- README.md | 1169 +++--------------------------- documentation/development.ja.md | 9 + documentation/development.md | 9 + 4 files changed, 237 insertions(+), 2147 deletions(-) diff --git a/README.ja.md b/README.ja.md index c8a44443..afe18b89 100644 --- a/README.ja.md +++ b/README.ja.md @@ -5,979 +5,141 @@ TypeScriptで実装された軽量なCLIタスク管理ツールです。エージェント(AIアシスタント)との協働作業に最適化されています。 -## 特徴 - -- **シンプルなCLI**: 直感的なコマンドラインインターフェース -- **SQLiteベース**: ローカルでの高速データ管理 -- **カンバン形式**: 7つのステータスでタスクを管理(icebox, backlog, ready, in_progress, review, done, closed) -- **柔軟な入力**: コマンドライン引数またはMarkdownファイルからタスクを作成 -- **フィルタリング**: ステータスや作成者でタスクを絞り込み -- **色分け表示**: ステータスごとに見やすい色分け表示 -- **親子関係**: タスクの階層構造を管理(ツリー表示対応) -- **ブロック関係**: タスク間の依存関係を管理(循環参照検出機能付き) -- **タグ機能**: タスクにタグを付けて分類・検索が可能 +![agkan カンバンボード](docs/assets/readme-board.png) -## Agent Skills +## 目次 -agkanをClaude Codeのスキル(タスクの自動実行、プランニング、レビューなど)と連携して使用するには、以下のスキルパッケージをインストールしてください: +- [特徴](#特徴) +- [クイックスタート](#クイックスタート) +- [コマンド早見表](#コマンド早見表) +- [Claude Code連携](#claude-code連携) +- [設定](#設定) +- [タスクステータス](#タスクステータス) +- [ドキュメント](#ドキュメント) +- [ライセンス](#ライセンス) -- **[agkan-skills](https://github.com/gendosu/agkan-skills)** - agkanタスク管理用のClaude Codeスキル - -## インストール +## 特徴 -### 前提条件 +**タスク管理** +- シンプルで直感的なCLI。ステータスごとに色分けされた表示 +- SQLiteベースのローカルストレージ — サーバーやアカウント不要 +- 柔軟な入力: コマンドライン引数またはMarkdownファイルからタスクを作成 +- ステータス・作成者・タグでの絞り込み、キーワード検索 +- メタデータ: `priority` のようなキーバリューデータをタスクに付与 -- Node.js 20以上 -- npm +**依存関係** +- ツリー表示対応の親子関係 +- タスク間のブロック関係。循環参照は自動検出 +- タグによるタスクの分類・検索 -### npmからインストール(推奨) +**カンバンボード** +- ローカルWebベースのカンバンボードビューア(`agkan board`) +- 7ステータスのワークフロー: icebox, backlog, ready, in_progress, review, done, closed -グローバルコマンドとしてインストール: -```bash -npm install -g agkan -``` +**AI連携** +- タスクカードから直接Claudeの実行・プランニングが可能。ライブ出力ストリーム付き +- タスクごとの過去のClaude実行履歴(Run Logs) +- Claude Code向けの補完パッケージ [agkan-skills](https://github.com/gendosu/agkan-skills) -これで `agkan` コマンドがシステム全体で使用可能になります。 +## クイックスタート -### GitHubからインストール +Node.js 20以上が必要です。 -リポジトリから直接インストール: +**1. インストール** ```bash -npm install -g https://github.com/gendosu/agkan.git +npm install -g agkan ``` +リポジトリから直接インストールすることもできます: `npm install -g https://github.com/gendosu/agkan.git` -## 使用方法 - -### プロジェクトの初期化 - -プロジェクトディレクトリで `agkan init` を実行して agkan をセットアップします: - +**2. プロジェクトを初期化** ```bash agkan init ``` - -以下のファイルが作成されます: -- `.agkan.yml` — 設定ファイル -- `.agkan/` — データディレクトリ - -`agkan init` は `.claude/settings.local.json` に SessionStart hook も登録し、 -Claude Code のセッション開始時に最小限の agkan 使用ガイドを自動でロードします。 -hook は `agkan context --hook` を呼び出します。既存設定との競合を避けるため -冪等にマージし、関係のないキーには触れません。Claude Code を使わない場合は -生成されたファイルを無視しても問題ありません。 - -### タスクの作成 - -基本的なタスク作成: -```bash -agkan task add "タスクのタイトル" "タスクの説明" ``` - -オプション付きでタスク作成: -```bash -agkan task add "ログイン機能の実装" "ユーザー認証システムを実装" \ - --status ready \ - --author "developer-name" +✓ Created .agkan.yml +✓ Created .agkan/ ``` +これによりClaude CodeのSessionStart hookも登録され、セッション開始時に +最小限のagkan使用ガイドが自動でロードされます。Claude Codeを使わない場合は +無視して問題ありません。 -親タスクを指定してタスク作成: +**3. タスクを作成** ```bash -agkan task add "子タスク" "詳細な作業項目" --parent 1 +agkan task add "ログイン機能の実装" --status ready ``` - -Markdownファイルからタスク作成: -```bash -agkan task add "設計書レビュー" --file ./design-doc.md --status backlog ``` - -タグ付きでタスク作成(カンマ区切りのタグ名またはID、同じコマンドで付与): -```bash -agkan task add "ログイン機能の実装" --tag "frontend,urgent" +Task created with ID: 1 ``` +`--parent`、`--tag`、`--file` でさらにカスタマイズできます。 -### タスク一覧の表示 - -全タスクを表示: +**4. タスク一覧を表示** ```bash agkan task list ``` - -ツリー形式で表示(親子関係を含む): -```bash -agkan task list --tree -``` - -ルートタスクのみ表示(親を持たないタスク): -```bash -agkan task list --root-only -``` - -ステータスでフィルタリング: -```bash -agkan task list --status in_progress -``` - -作成者でフィルタリング: -```bash -agkan task list --author "developer-name" -``` - -複合フィルター: -```bash -agkan task list --status ready --author "developer-name" -``` - -タグでフィルタリング: -```bash -agkan task list --tag "frontend" -``` - -### タスクの検索 - -キーワードでタスクを検索(タイトルと本文を対象): -```bash -agkan task find "検索キーワード" -``` - -完了済みタスクも含めて検索: -```bash -agkan task find "検索キーワード" --all -``` - -注: デフォルトでは、`done`と`closed`のタスクは検索結果から除外されます。 - -### タスク詳細の取得 - -```bash -agkan task get 1 -``` - -### タスクの更新 - -ステータスを変更: -```bash -agkan task update 1 status done -``` - -タイトルを変更: -```bash -agkan task update 1 title "新しいタイトル" -``` - -本文を変更: -```bash -agkan task update 1 body "新しい説明文" -``` - -作成者を変更: -```bash -agkan task update 1 author "new-author" -``` - -### 親子関係の管理 - -親タスクの更新: -```bash -# タスク2の親をタスク1に設定 -agkan task update-parent 2 1 - -# タスク2の親を解除(孤立化) -agkan task update-parent 2 null -``` - -注意事項: -- 親タスクを削除すると、子タスクの親参照は自動的に解除されます(孤立化) -- 循環参照は自動的に検出され、エラーとなります - -### ブロック関係の管理 - -ブロック関係の追加(タスク1がタスク2をブロック): -```bash -agkan task block add 1 2 -``` - -ブロック関係の削除: -```bash -agkan task block remove 1 2 -``` - -ブロック関係の一覧表示: -```bash -# タスク1に関連するブロック関係を表示 -agkan task block list 1 -``` - -注意事項: -- 循環参照は自動的に検出され、エラーとなります -- ブロック関係はタスク削除時に自動的に削除されます(CASCADE DELETE) - -### タスクの削除 - -タスクを削除: -```bash -agkan task delete 1 -``` - -### タグ管理 - -タグを作成: -```bash -agkan tag add "frontend" -``` - -タグ一覧を表示: -```bash -agkan tag list -``` - -タグを削除: -```bash -agkan tag delete "frontend" -``` - -### タスクへのタグ付け - -タスクにタグを付与: -```bash -agkan tag attach 1 "frontend" ``` - -または `task add --tag` でタスク作成と同時にタグを付与(`tag attach` を別途実行する必要がない): -```bash -agkan task add "ログイン画面の実装" --tag "frontend,urgent" +1 [ready] ログイン機能の実装 ``` +`--tree` で親子関係を含めて表示、`--status`/`--tag` で絞り込みができます。 -タスクからタグを削除: -```bash -agkan tag detach 1 "frontend" -``` - -タスクに付けられたタグを表示: -```bash -agkan tag show 1 -``` - -### メタデータの管理 - -メタデータを設定: -```bash -agkan task meta set 1 priority high -``` - -メタデータを取得: -```bash -agkan task meta get 1 priority -``` - -メタデータ一覧を表示: -```bash -agkan task meta list 1 -``` - -メタデータを削除: -```bash -agkan task meta delete 1 priority -``` - -#### 優先度 (priority) - -タスクの優先度は `priority` キーで管理します: - -| 値 | 意味 | -|-----|------| -| `critical` | 即時対応が必要。ブロッカーとなっている問題 | -| `high` | 優先して着手すべきタスク | -| `medium` | 通常の優先度(デフォルト) | -| `low` | 余裕があれば対応するタスク | - -### タスクのカウント - -全ステータスのタスク数を表示: -```bash -agkan task count -``` - -特定のステータスのタスク数を表示: -```bash -agkan task count --status in_progress -``` - -スクリプト用の出力(数値のみ): -```bash -agkan task count -s in_progress -q -``` - -### カンバンボード (Web UI) - -ブラウザでローカルのカンバンボードビューアを起動: +**5. カンバンボードを開く** ```bash agkan board ``` - -カスタムポートを指定: -```bash -agkan board -p 3000 -``` - -デフォルトでは `http://localhost:8080` でボードが提供されます。 - -#### ボードのClaude連携機能 - -ボードUIにはブラウザから直接Claudeを実行するための機能が組み込まれています: - -- **Runボタン**: タスクカードにある「Run」ボタンをクリックすると、そのタスクに対して `claude` を起動します。ボタン横のドロップダウンからプランモードで実行することもできます。 -- **Planボタン**: タスクを実行せずに計画のみを生成するプランモードで `claude` を起動します。 -- **ストリームモーダル**: Claude実行中はモーダルウィンドウにリアルタイムで出力が表示されます。「Stop」ボタンでプロセスを終了できます。 -- **実行中インジケーター**: Claudeプロセスが動作中の場合、ヘッダーにインジケーターが表示されます。 -- **実行ログタブ**: タスク詳細パネルの「Run Logs」タブに、過去のClaude実行履歴(タイムスタンプと全出力)が表示されます。 - -### Claudeプロセスの状態確認 - -現在実行中のClaudeプロセスを一覧表示します(ボードサーバーが起動している必要があります): -```bash -agkan ps -``` - -カスタムポートのボードサーバーに接続: -```bash -agkan ps --port 3000 -``` - -このコマンドはボードサーバーに問い合わせて、現在実行中のClaudeプロセスとそれに関連するタスクを表示します。 - -JSON出力フォーマット: -```bash -agkan ps --json -``` -```json -{ - "processes": [ - { - "taskId": 42, - "title": "機能Xの実装", - "command": "claude" - } - ] -} -``` - -### 設定確認 - -`.agkan.yml` の設定値(デフォルト適用後の解決済み値)を取得します: - -```bash -agkan config get # 全設定を表示 -agkan config get board.port # 特定キーを取得(ドット記法) -agkan config get --json # JSON出力 -``` - -出力例: -``` -✓ Resolved config - -path: /workspace/.agkan/data.db -board.port: 8080 -``` - -### ヘルプの表示 - -コマンド一覧: -```bash -agkan --help -``` - -タスクコマンドのヘルプ: -```bash -agkan task --help -``` - -個別コマンドのヘルプ: -```bash -agkan task add --help -``` - -## JSON出力フォーマット - -agkanは10のデータ取得・表示コマンドで、機械可読なJSON出力をサポートしています。`--json`フラグを追加することで、人間が読みやすいテキストの代わりに構造化されたデータを出力できます。 - -### 対応コマンド - -以下のコマンドがJSON出力をサポートしています: - -- `task add` - 新しいタスクを作成 -- `task list` - タスク一覧を表示(フィルタリング付き) -- `task get` - タスク詳細を取得 -- `task find` - キーワードでタスクを検索 -- `task count` - ステータス別のタスク数をカウント -- `task update-parent` - 親子関係を更新 -- `task block list` - ブロック関係を一覧表示 -- `task tag list` - 全タグをタスク数と共に一覧表示 -- `task tag show` - 特定のタスクのタグを表示 -- `task meta list` - タスクのメタデータ一覧を表示 -- `ps` - 現在実行中のClaudeプロセスを一覧表示 - -### 出力構造 - -すべてのJSONレスポンスは以下のパターンに従います: - -**成功レスポンス**には以下が含まれます: -- 操作固有のデータ(task、tasksの配列、counts など) -- 関連データ(parent、blockedBy、blocking、tags など) -- 書き込み操作の場合はオプションで`success: true`フィールド - -**エラーレスポンス**は以下のフォーマットに従います: -```json -{ - "success": false, - "error": { - "message": "エラーの説明" - } -} -``` - -### 一般的な使用例 - -**1. スクリプティングと自動化** -```bash -# CI/CDパイプライン用のタスク数を取得 -TASK_COUNT=$(agkan task count --status backlog --json | jq '.counts.backlog') - -# 処理用にタスクIDを抽出 -agkan task list --status ready --json | jq -r '.tasks[].id' -``` - -**2. 他ツールとの統合** -```bash -# タスクを外部システムにエクスポート -agkan task list --json | jq '.tasks' > tasks.json - -# ブロック関係を処理 -agkan task block list 1 --json | jq '.blockedBy[].title' -``` - -**3. 検証とテスト** -```bash -# タスク作成を検証 -RESULT=$(agkan task add "Test" --json) -echo $RESULT | jq -e '.success == true' && echo "Success" ``` - -JSON出力フォーマット: -```bash -agkan task add "Fix bug in login" --json -``` - -```json -{ - "success": true, - "task": { - "id": 1, - "title": "Fix bug in login", - "status": "backlog", - "body": null, - "author": null, - "parent_id": null, - "created_at": "2026-02-15T00:00:00.000Z", - "updated_at": "2026-02-15T00:00:00.000Z" - }, - "parent": null, - "blockedBy": [], - "blocking": [] -} -``` - -JSON出力フォーマット: -```bash -agkan task list --json -``` - -```json -{ - "tasks": [ - { - "id": 1, - "title": "Implement login feature", - "status": "in_progress", - "body": "Implement user authentication system", - "author": "developer-name", - "parent_id": null, - "created_at": "2026-02-15T00:00:00.000Z", - "updated_at": "2026-02-15T00:00:00.000Z" - }, - { - "id": 2, - "title": "Design review", - "status": "backlog", - "body": null, - "author": null, - "parent_id": null, - "created_at": "2026-02-15T00:00:00.000Z", - "updated_at": "2026-02-15T00:00:00.000Z" - } - ] -} -``` - -JSON出力フォーマット: -```bash -agkan task find "login" --json -``` - -```json -{ - "tasks": [ - { - "id": 1, - "title": "Implement login feature", - "status": "in_progress", - "body": "Implement user authentication system", - "author": "developer-name", - "parent_id": null, - "created_at": "2026-02-15T00:00:00.000Z", - "updated_at": "2026-02-15T00:00:00.000Z" - } - ] -} -``` - -JSON出力フォーマット: -```bash -agkan task get 1 --json -``` - -```json -{ - "task": { - "id": 1, - "title": "Implement login feature", - "status": "in_progress", - "body": "Implement user authentication system", - "author": "developer-name", - "parent_id": null, - "created_at": "2026-02-15T00:00:00.000Z", - "updated_at": "2026-02-15T00:00:00.000Z" - } -} -``` - -JSON出力フォーマット: -```bash -agkan task update-parent 2 1 --json -``` - -```json -{ - "success": true, - "task": { - "id": 2, - "title": "Child Task", - "status": "backlog", - "body": null, - "author": null, - "parent_id": 1, - "created_at": "2026-02-15T00:00:00.000Z", - "updated_at": "2026-02-15T00:00:00.000Z" - }, - "parent": { - "id": 1, - "title": "Parent Task", - "status": "backlog", - "body": null, - "author": null, - "parent_id": null, - "created_at": "2026-02-15T00:00:00.000Z", - "updated_at": "2026-02-15T00:00:00.000Z" - } -} -``` - -JSON出力フォーマット: -```bash -agkan task block list 2 --json -``` - -```json -{ - "task": { - "id": 2, - "title": "API implementation", - "status": "backlog" - }, - "blockedBy": [ - { - "id": 1, - "title": "Database design", - "status": "in_progress" - } - ], - "blocking": [ - { - "id": 3, - "title": "Frontend implementation", - "status": "backlog" - } - ] -} -``` - -全ステータスのJSON出力フォーマット: -```bash -agkan task count --json -``` - -```json -{ - "total": 10, - "counts": { - "backlog": 3, - "ready": 2, - "in_progress": 4, - "done": 1, - "closed": 0 - } -} -``` - -特定ステータスのJSON出力フォーマット: -```bash -agkan task count --status in_progress --json -``` - -```json -{ - "status": "in_progress", - "count": 4 -} -``` - -JSON出力フォーマット: -```bash -agkan tag list --json -``` - -```json -{ - "totalCount": 2, - "tags": [ - { - "id": 1, - "name": "frontend", - "taskCount": 3, - "created_at": "2026-02-15T00:00:00.000Z" - }, - { - "id": 2, - "name": "backend", - "taskCount": 1, - "created_at": "2026-02-15T00:00:00.000Z" - } - ] -} -``` - -JSON出力フォーマット: -```bash -agkan tag show 1 --json -``` - -```json -{ - "task": { - "id": 1, - "title": "Implement login screen", - "status": "in_progress" - }, - "tags": [ - { - "id": 1, - "name": "frontend", - "created_at": "2026-02-15T00:00:00.000Z" - }, - { - "id": 3, - "name": "urgent", - "created_at": "2026-02-15T00:00:00.000Z" - } - ] -} -``` - -## 使用例 - -### 親子関係を使った階層的なタスク管理 - -プロジェクトを親タスク、個別の作業を子タスクとして管理する例: - -```bash -# 親タスクを作成 -agkan task add "Webサイトのリニューアル" -# 出力: Task created with ID: 1 - -# 子タスクを作成 -agkan task add "デザインカンプ作成" --parent 1 -agkan task add "フロントエンド実装" --parent 1 -agkan task add "バックエンド実装" --parent 1 - -# ツリー形式で表示 -agkan task list --tree -# 出力: -# 1 [backlog] Webサイトのリニューアル -# ├─ 2 [backlog] デザインカンプ作成 -# ├─ 3 [backlog] フロントエンド実装 -# └─ 4 [backlog] バックエンド実装 - -# タスク詳細を表示(親情報を含む) -agkan task get 2 -# 出力: -# ID: 2 -# Title: デザインカンプ作成 -# Parent ID: 1 -# ... - -# 親を変更 -agkan task add "UI/UX改善" -# 出力: Task created with ID: 5 -agkan task update-parent 2 5 - -# 親を解除(孤立化) -agkan task update-parent 2 null -``` - -### ブロック関係を使った依存関係の管理 - -タスク間の依存関係を明示的に管理する例: - -```bash -# タスクを作成 -agkan task add "データベース設計" -# 出力: Task created with ID: 1 - -agkan task add "API実装" -# 出力: Task created with ID: 2 - -agkan task add "フロントエンド実装" -# 出力: Task created with ID: 3 - -# ブロック関係を設定(1がデータベース設計、2がAPI実装、3がフロントエンド実装) -# データベース設計がAPI実装をブロック -agkan task block add 1 2 - -# API実装がフロントエンド実装をブロック -agkan task block add 2 3 - -# ブロック関係を確認 -agkan task block list 1 -# 出力: -# Task 1 blocks: -# - Task 2 (API実装) -# Task 1 is blocked by: -# (none) - -agkan task block list 2 -# 出力: -# Task 2 blocks: -# - Task 3 (フロントエンド実装) -# Task 2 is blocked by: -# - Task 1 (データベース設計) - -# 循環参照を試みる(エラーになる) -agkan task block add 3 1 -# 出力: Error: Circular reference detected - -# ブロック関係を削除 -agkan task block remove 1 2 -``` - -### タグを使ったタスク管理 - -タスクにタグを付けて分類する例: - -```bash -# タグを作成 -agkan tag add "frontend" -agkan tag add "backend" -agkan tag add "urgent" - -# タスクを作成してタグを付与 -agkan task add "ログイン画面の実装" -# 出力: Task created with ID: 1 - -agkan tag attach 1 "frontend" -agkan tag attach 1 "urgent" - -agkan task add "API開発" -# 出力: Task created with ID: 2 - -agkan tag attach 2 "backend" - -# --tag を使えば同じコマンドでタグを付与できる -agkan task add "決済フローのバグ修正" --tag "backend,urgent" -# 出力: Task created with ID: 3 - -# タグでフィルタリング -agkan task list --tag "frontend" -# 出力: -# 1 [backlog] ログイン画面の実装 (tags: frontend, urgent) - -# タスクのタグを確認 -agkan tag show 1 -# 出力: -# Tags for task 1: -# - frontend -# - urgent - -# タグを削除 -agkan tag detach 1 "urgent" - -# タグ自体を削除(関連するすべてのタスクから削除される) -agkan tag delete "urgent" -``` - -## タスクステータス - -- **icebox**: 積極的に検討していない凍結タスク(白色表示) -- **backlog**: 未着手のタスク(グレー表示) -- **ready**: 着手可能なタスク(青色表示) -- **in_progress**: 作業中のタスク(黄色表示) -- **review**: レビュー中のタスク(シアン表示) -- **done**: 完了したタスク(緑色表示) -- **closed**: クローズされたタスク(マゼンタ表示) +Board running at http://localhost:8080 +``` +ポートは `agkan board -p 3000` または `.agkan.yml` の `board.port` でカスタマイズできます。 + +## コマンド早見表 + +全コマンドの一行サマリー: + +| コマンド | 説明 | +|---------|------| +| `agkan init` | プロジェクトでagkanを初期化 | +| `agkan task add` | タスクを新規作成 | +| `agkan task list` | タスク一覧を表示(フィルタ付き) | +| `agkan task find` | キーワードでタスクを検索 | +| `agkan task get` | タスク詳細を表示 | +| `agkan task update` | タスクのステータス・タイトル・本文・作成者を更新 | +| `agkan task update-parent` | タスクの親を設定・解除 | +| `agkan task block add` | ブロック関係を追加 | +| `agkan task block remove` | ブロック関係を削除 | +| `agkan task block list` | タスクのブロック関係を一覧表示 | +| `agkan task delete` | タスクを削除 | +| `agkan tag add` | タグを作成 | +| `agkan tag list` | タグ一覧を表示 | +| `agkan tag delete` | タグを削除 | +| `agkan tag attach` | タスクにタグを付与 | +| `agkan tag detach` | タスクからタグを削除 | +| `agkan tag show` | タスクのタグを表示 | +| `agkan task meta set` | タスクにメタデータキーを設定 | +| `agkan task meta get` | タスクのメタデータ値を取得 | +| `agkan task meta list` | タスクの全メタデータを一覧表示 | +| `agkan task meta delete` | タスクからメタデータキーを削除 | +| `agkan task count` | ステータス別のタスク数をカウント | +| `agkan board` | ローカルカンバンボードビューアを起動 | +| `agkan ps` | 現在実行中のClaudeプロセスを一覧表示 | +| `agkan config get` | 解決済みの設定値を表示 | +| `agkan --help` | コマンドヘルプを表示 | + +各コマンドは該当する箇所で`--json`による機械可読な出力に対応しており、上記の多くのコマンドには追加オプションもあります。全オプション一覧・JSON出力フォーマット・使用例は **[documentation/cli-reference.ja.md](documentation/cli-reference.ja.md)** を参照してください。 + +## Claude Code連携 + +カンバンボードにはブラウザから直接Claudeを実行するための機能が組み込まれています: + +- **Run** — タスクに対して `claude` を起動。ボタン横のドロップダウンからプランモードでの実行も可能 +- **Plan** — 実行せずに計画のみを生成するプランモードで `claude` を起動 +- **ストリームモーダル** — 実行中のClaudeプロセスのライブ出力を表示。Stopボタンで終了可能 +- **実行中インジケーター** — Claudeプロセスが動作中の場合、ヘッダーにインジケーターを表示 +- **Run Logs** — タスク詳細パネルのタブに、過去のClaude実行履歴(タイムスタンプと全出力)を表示 + +自動でのタスク実行・プランニング・レビューのワークフローには、Claude Code向けの補完パッケージ **[agkan-skills](https://github.com/gendosu/agkan-skills)** をインストールしてください。 ## 設定 -### データベースの保存場所 - -agkanは、データベースの保存場所を設定ファイルでカスタマイズできます。 - -#### 設定ファイル: `.agkan.yml` - -プロジェクトのルートディレクトリに`.agkan.yml`ファイルを作成することで、データベースの保存場所を指定できます。 - -**設定例:** - -```yaml -# データベースファイルのパス -path: ./.agkan/data.db -``` - -#### パスの指定方法 - -- **相対パス**: カレントディレクトリからの相対パスとして解決されます - ```yaml - path: ./data/kanban.db - path: ./.agkan/data.db - ``` - -- **絶対パス**: そのままのパスが使用されます - ```yaml - path: /home/user/.config/agkan/data.db - ``` - -#### 環境変数による設定 - -agkanは `AGENT_KANBAN_DB_PATH` 環境変数によるデータベースの場所指定をサポートしています。CI/CD環境や複数環境の管理に特に有用です。 - -**環境変数の設定例:** - -```bash -# カスタムデータベースパスを使用 -export AGENT_KANBAN_DB_PATH=/path/to/your/database.db -agkan task list - -# 絶対パスを使用 -export AGENT_KANBAN_DB_PATH=/home/user/.config/agkan/data.db - -# 相対パスを使用 -export AGENT_KANBAN_DB_PATH=./custom/location/data.db -``` - -**優先順位:** - -データベースパスは以下の優先順位で解決されます: - -**通常モード (`NODE_ENV` が `test` でない場合):** -1. **環境変数**(最高優先): `AGENT_KANBAN_DB_PATH` -2. **設定ファイル**(フォールバック): `.agkan.yml` の `path` フィールド -3. **デフォルトパス**(最低優先): `.agkan/data.db` - -**テストモード (`NODE_ENV=test` の場合):** -1. **環境変数**(最高優先): `AGENT_KANBAN_DB_PATH` -2. **設定ファイル**(フォールバック): `.agkan-test.yml` の `path` フィールド -3. **デフォルトパス**(最低優先): `.agkan-test/data.db` - -**テストモードについて:** - -テストモード(`NODE_ENV=test`)では、テストデータと本番データを自動的に分離します: - -- 別の設定ファイルを使用: `.agkan.yml` の代わりに `.agkan-test.yml` -- 別のデフォルトディレクトリを使用: `.agkan/` の代わりに `.agkan-test/` -- テストモードでも環境変数が最高優先になります - -**使用例:** - -```bash -# CI/CDパイプライン(一時DBを使用) -export AGENT_KANBAN_DB_PATH=/tmp/ci-test-db.db -agkan task list - -# 複数環境の管理 -export AGENT_KANBAN_DB_PATH=./dev/data.db # 開発環境 -export AGENT_KANBAN_DB_PATH=./staging/data.db # ステージング環境 - -# テストの実行 -NODE_ENV=test pnpm test -# デフォルトで .agkan-test/data.db を使用 - -# カスタムテストDBで実行 -NODE_ENV=test AGENT_KANBAN_DB_PATH=/tmp/test.db pnpm test -``` - -#### デフォルトの動作 - -`.agkan.yml`ファイルが存在せず、環境変数も設定されていない場合、データベースは以下の場所に作成されます: - -``` -<カレントディレクトリ>/.agkan/data.db -``` - -テストモード(`NODE_ENV=test`)の場合のデフォルト: - -``` -<カレントディレクトリ>/.agkan-test/data.db -``` - -#### プロジェクトごとの管理 - -プロジェクトごとに異なるタスク管理を行いたい場合は、各プロジェクトのルートに`.agkan.yml`を配置してください: - -```bash -# プロジェクトA -cd /path/to/projectA -cat > .agkan.yml << EOF -path: ./.agkan/data.db -EOF - -# プロジェクトB -cd /path/to/projectB -cat > .agkan.yml << EOF -path: ./.agkan/data.db -EOF -``` - -これにより、各プロジェクトで独立したタスク管理が可能になります。 - -### ボード設定 - -`.agkan.yml` の `board` セクションでは、`agkan board` コマンドの動作をカスタマイズできます。 - -#### 利用可能なフィールド - -| フィールド | 型 | デフォルト値 | 説明 | -|----------|-----|------------|------| -| `board.port` | number | `3000` | ボードWebサーバーのポート番号 | -| `board.title` | string | `"agkan Board"` | ボードUIに表示されるタイトル | - -#### 設定例 +プロジェクトのルートに `.agkan.yml` を作成してagkanをカスタマイズします: ```yaml # データベースファイルのパス @@ -986,148 +148,39 @@ path: ./.agkan/data.db # ボード設定 board: port: 8080 - title: "マイプロジェクトボード" -``` - -#### フィールドの詳細 - -- **`board.port`**: ボードWebサーバーがリッスンするTCPポートを指定します。デフォルトポート `3000` が既に使用中の場合に有用です。 - ```yaml - board: - port: 8080 - ``` - -- **`board.title`**: ボードUIに表示されるタイトルを設定します。複数のプロジェクトを管理する際に、ボードを区別するのに役立ちます。 - ```yaml - board: - title: "マイプロジェクトボード" - ``` - -### モデル設定 - -`.agkan.yml` の `models` セクションでは、ボード経由でplanningおよびrunコマンドを実行する際に使用するClaudeモデルとeffortレベルを指定できます。 - -#### 利用可能なフィールド - -| フィールド | 型 | デフォルト値 | 説明 | -|----------|-----|------------|------| -| `models.planning.model` | string | (Claude CLIのデフォルト) | planningコマンド実行時に使用するモデル | -| `models.planning.effort` | string | (Claude CLIのデフォルト) | planningコマンドのeffortレベル(`low`, `medium`, `high`, `xhigh`, `max`) | -| `models.run.model` | string | (Claude CLIのデフォルト) | run/prコマンド実行時に使用するモデル | -| `models.run.effort` | string | (Claude CLIのデフォルト) | run/prコマンドのeffortレベル(`low`, `medium`, `high`, `xhigh`, `max`) | - -フルモデル名とClaude CLIのエイリアスの両方が使用できます。`model` と `effort` はいずれも省略可能です。 - -#### 設定例 - -```yaml -# データベースファイルのパス -path: ./.agkan/data.db - -# モデル設定 -models: - planning: - model: claude-opus-4-7 - effort: high - run: - model: claude-sonnet-4-6 - effort: low -``` - -#### エイリアスの使用 - -フルモデル名の代わりに短いエイリアスを使用できます: - -```yaml -models: - planning: - model: opus - effort: high - run: - model: sonnet -``` - -使用可能なエイリアス: `opus`、`sonnet`、`haiku`(Claude CLIが解決します) - -#### フィールドの詳細 - -- **`models.planning`**: ボードがplanningタスクを実行する際に使用するClaudeモデルとeffortレベルを指定します。`opus` や `claude-opus-4-7` など高性能なモデルと高いeffortレベルの使用を推奨します。 - ```yaml - models: - planning: - model: opus - effort: high - ``` - -- **`models.run`**: ボードがrunまたはprコマンドを実行する際に使用するClaudeモデルとeffortレベルを指定します。`pr` コマンドもこの値を使用します。 - ```yaml - models: - run: - model: sonnet - effort: low - ``` - -### パーミッションモード設定 - -`.agkan.yml` の `permissionMode` フィールドで、ボードからタスクを実行する際のClaude CLIのパーミッションチェック方法を制御できます。 - -#### 利用可能な値 - -| 値 | Claude CLI フラグ | 説明 | -|-------|----------------|-------------| -| (未設定) | `--permission-mode auto` | デフォルト。Claudeがautoパーミッションモードを使用 | -| `auto` | `--permission-mode auto` | Claudeがautoパーミッションモードを使用 | -| `bypassPermissions` | `--permission-mode bypassPermissions` | すべてのパーミッションチェックをバイパス | -| `acceptEdits` | `--permission-mode acceptEdits` | ファイル編集を自動的に承認 | -| `dontAsk` | `--permission-mode dontAsk` | パーミッションを確認しない | -| `plan` | `--permission-mode plan` | プランのみモード | -| `default` | `--permission-mode default` | Claudeのデフォルトパーミッションモード | -| `skipPermissions` | `--dangerously-skip-permissions` | レガシーフラグ(すべてのチェックをバイパスする旧来の動作) | - -#### 設定例 - -```yaml -# autoパーミッションモードを使用(デフォルト) -permissionMode: auto - -# レガシーの --dangerously-skip-permissions フラグを使用 -permissionMode: skipPermissions ``` -> **破壊的変更**: この機能導入以前は常に `--dangerously-skip-permissions` が渡されていました。新しいデフォルトは `--permission-mode auto` です。従来の動作を維持するには `.agkan.yml` に `permissionMode: skipPermissions` を設定してください。 - -## 実装予定機能 - -### タスクの添付ファイル - -タスクへのファイル添付機能は現在開発中です。この機能により、ユーザーはタスクにファイルを添付し、より良いコンテキストとドキュメントを提供できるようになります。 - -**予定されているCLIコマンド:** -- `agkan task attach add ` - タスクにファイルを添付 -- `agkan task attach list ` - タスクのすべての添付ファイルを一覧表示 -- `agkan task attach delete ` - タスクから添付ファイルを削除 +データベースパスは `AGENT_KANBAN_DB_PATH` 環境変数でも上書きでき、`.agkan.yml` より優先されます。 -実装予定機能の詳細については、[documentation/planned-features.md](documentation/planned-features.md)を参照してください。 +`.agkan.yml` は以下もサポートしています: +- `models.planning` / `models.run` — ボードからplanning/runタスクを実行する際に使用するClaudeモデルとeffortレベル +- `permissionMode` — ボードからタスクを実行する際に渡されるClaude CLIのパーミッションフラグ -## 技術スタック +全フィールドリファレンス・パス解決の優先順位・テストモードの挙動については **[documentation/configuration.ja.md](documentation/configuration.ja.md)** を参照してください。 -- **言語**: TypeScript 5.x -- **CLI フレームワーク**: Commander.js -- **データベース**: SQLite3 (better-sqlite3) -- **ターミナル表示**: Chalk -- **ビルドツール**: TypeScript Compiler - -## プロジェクト構成 - -詳細なディレクトリ構成は [documentation/project-structure.ja.md](documentation/project-structure.ja.md) を参照してください。 - -## データベーススキーマ - -詳細なスキーマ情報は [documentation/database-schema.ja.md](documentation/database-schema.ja.md) を参照してください。 - -## 開発 +## タスクステータス -セットアップ手順、テスト、ビルド情報については [documentation/development.ja.md](documentation/development.ja.md) を参照してください。 +| ステータス | 意味 | ボード表示色 | +|-----------|------|-------------| +| `icebox` | 積極的に検討していない凍結タスク | 白 | +| `backlog` | 未着手 | グレー | +| `ready` | 着手可能 | 青 | +| `in_progress` | 作業中 | 黄 | +| `review` | レビュー中 | シアン | +| `done` | 完了 | 緑 | +| `closed` | クローズ | マゼンタ | + +## ドキュメント + +| ドキュメント | 説明 | +|-------------|------| +| [documentation/cli-reference.ja.md](documentation/cli-reference.ja.md) | 全コマンドリファレンス・オプション・JSON出力フォーマット | +| [documentation/configuration.ja.md](documentation/configuration.ja.md) | `.agkan.yml` の全フィールドリファレンス | +| [documentation/database-schema.ja.md](documentation/database-schema.ja.md) | データベーススキーマリファレンス | +| [documentation/project-structure.ja.md](documentation/project-structure.ja.md) | ディレクトリ構成 | +| [documentation/development.ja.md](documentation/development.ja.md) | 開発者向けセットアップ・技術スタック・テスト・ビルド | +| [CONTRIBUTING.ja.md](CONTRIBUTING.ja.md) | コントリビューションガイドラインとTDDプラクティス | +| [CHANGELOG.ja.md](CHANGELOG.ja.md) | リリース履歴 | ## ライセンス diff --git a/README.md b/README.md index 14103226..690fb72d 100644 --- a/README.md +++ b/README.md @@ -3,1146 +3,165 @@ [![Test](https://github.com/gendosu/agkan/workflows/Test/badge.svg?branch=main)](https://github.com/gendosu/agkan/actions/workflows/test.yml) [![Quality Check](https://github.com/gendosu/agkan/workflows/Quality%20Check/badge.svg?branch=main)](https://github.com/gendosu/agkan/actions/workflows/quality.yml) -A lightweight CLI task management tool implemented in TypeScript. Optimized for collaborative work with AI agents. +A lightweight CLI task management tool, built for humans and AI coding agents working together. -## Features - -- **Simple CLI**: Intuitive command-line interface -- **SQLite-based**: Fast local data management -- **Kanban Format**: Manage tasks with 7 statuses (icebox, backlog, ready, in_progress, review, done, closed) -- **Flexible Input**: Create tasks from command-line arguments or Markdown files -- **Filtering**: Narrow down tasks by status or author -- **Color-coded Display**: Easy-to-read color-coded display by status -- **Parent-Child Relationships**: Manage task hierarchy (tree view supported) -- **Blocking Relationships**: Manage task dependencies (includes circular reference detection) -- **Tag System**: Classify and search tasks with tags -- **Kanban Board**: Local web-based Kanban board viewer +![agkan Kanban board](docs/assets/readme-board.png) -## Agent Skills +## Features -To use agkan with Claude Code skills (automated task execution, planning, review, etc.), install the companion skills package: +**Task Management** +- Simple, intuitive CLI backed by local SQLite storage +- 7-status Kanban workflow: icebox, backlog, ready, in_progress, review, done, closed +- Create tasks from CLI arguments or Markdown files; filter by status, author, or tag +- Color-coded terminal output -- **[agkan-skills](https://github.com/gendosu/agkan-skills)** - Claude Code skills for agkan task management +**Dependencies** +- Parent-child relationships with tree view (`task list --tree`) +- Blocking relationships with automatic circular-reference detection +- Tag system for classifying and searching tasks -## Installation +**Kanban Board** +- Local, zero-config web UI (`agkan board`) +- Filter and browse tasks by status, tag, or author in the browser -### Prerequisites +**AI Integration** +- Machine-readable JSON output on key commands for scripting and automation +- Companion [agkan-skills](https://github.com/gendosu/agkan-skills) package for Claude Code +- Run Claude directly from the board, with live streaming output and run history -- Node.js 20 or higher -- npm +## Quick Start -### Install from npm (Recommended) +### 1. Install -Install as a global command: ```bash npm install -g agkan ``` -Now the `agkan` command is available system-wide. - -### Install from GitHub - -Install directly from the repository: +Requires Node.js 20+ and npm. To install the latest code directly from GitHub instead: ```bash npm install -g https://github.com/gendosu/agkan.git ``` -## Usage - -### Initialize a Project - -Run `agkan init` in your project directory to set up agkan: +### 2. Initialize your project ```bash agkan init ``` - -This creates: -- `.agkan.yml` — configuration file -- `.agkan/` — data directory - -`agkan init` also installs a SessionStart hook into `.claude/settings.local.json` -so that Claude Code automatically loads a minimal agkan usage brief at the -start of every session. The hook calls `agkan context --hook`. This step is -idempotent and merges into existing settings without touching unrelated keys. -If you are not using Claude Code, you can safely ignore the generated file. - -### Create Tasks - -Basic task creation: -```bash -agkan task add "Task title" "Task description" -``` - -Create with options: -```bash -agkan task add "Implement login feature" "Implement user authentication system" \ - --status ready \ - --author "developer-name" ``` - -Create with parent task: -```bash -agkan task add "Subtask" "Detailed work item" --parent 1 +Created: .agkan.yml +Created: .agkan/ directory +Created: .claude/settings.local.json (added agkan SessionStart hook) ``` -Create from Markdown file: -```bash -agkan task add "Design review" --file ./design-doc.md --status backlog -``` +### 3. Create a task -Create with tags (comma-separated names or IDs, attached in the same command): ```bash -agkan task add "Implement login feature" --tag "frontend,urgent" +agkan task add "Implement login feature" "Implement user authentication system" ``` - -JSON output format: -```bash -agkan task add "Fix bug in login" --json ``` +✓ Task created successfully -```json -{ - "success": true, - "task": { - "id": 1, - "title": "Fix bug in login", - "status": "backlog", - "body": null, - "author": null, - "parent_id": null, - "created_at": "2026-02-15T00:00:00.000Z", - "updated_at": "2026-02-15T00:00:00.000Z" - }, - "parent": null, - "blockedBy": [], - "blocking": [] -} +ID: 1 +Title: Implement login feature +Status: backlog +Created: 2026/7/10 15:02:48 ``` -### List Tasks +### 4. List tasks -Display all tasks: ```bash agkan task list ``` - -Display in tree format (including parent-child relationships): -```bash -agkan task list --tree ``` +Found 1 task(s): -Display root tasks only (tasks without parents): -```bash -agkan task list --root-only -``` - -Filter by status: -```bash -agkan task list --status in_progress -``` - -Filter by author: -```bash -agkan task list --author "developer-name" -``` - -Combined filters: -```bash -agkan task list --status ready --author "developer-name" -``` +──────────────────────────────────────────────────────────────────────────────── -Filter by tag: -```bash -agkan task list --tag "frontend" -``` - -JSON output format: -```bash -agkan task list --json -``` - -```json -{ - "tasks": [ - { - "id": 1, - "title": "Implement login feature", - "status": "in_progress", - "body": "Implement user authentication system", - "author": "developer-name", - "parent_id": null, - "created_at": "2026-02-15T00:00:00.000Z", - "updated_at": "2026-02-15T00:00:00.000Z" - }, - { - "id": 2, - "title": "Design review", - "status": "backlog", - "body": null, - "author": null, - "parent_id": null, - "created_at": "2026-02-15T00:00:00.000Z", - "updated_at": "2026-02-15T00:00:00.000Z" - } - ] -} -``` - -### Search Tasks - -Search by keyword (in title and body): -```bash -agkan task find "search keyword" -``` - -Include completed tasks in search: -```bash -agkan task find "search keyword" --all +[1] Implement login feature + Status: backlog + Priority: medium + Created: 2026/7/10 15:02:48 ``` -Note: By default, `done` and `closed` tasks are excluded from search results. +### 5. Open the Kanban board -JSON output format: -```bash -agkan task find "login" --json -``` - -```json -{ - "tasks": [ - { - "id": 1, - "title": "Implement login feature", - "status": "in_progress", - "body": "Implement user authentication system", - "author": "developer-name", - "parent_id": null, - "created_at": "2026-02-15T00:00:00.000Z", - "updated_at": "2026-02-15T00:00:00.000Z" - } - ] -} -``` - -### Get Task Details - -```bash -agkan task get 1 -``` - -JSON output format: -```bash -agkan task get 1 --json -``` - -```json -{ - "task": { - "id": 1, - "title": "Implement login feature", - "status": "in_progress", - "body": "Implement user authentication system", - "author": "developer-name", - "parent_id": null, - "created_at": "2026-02-15T00:00:00.000Z", - "updated_at": "2026-02-15T00:00:00.000Z" - } -} -``` - -### Update Tasks - -Change status: -```bash -agkan task update 1 status done -``` - -Change title: -```bash -agkan task update 1 title "New title" -``` - -Change body: -```bash -agkan task update 1 body "New description" -``` - -Change author: -```bash -agkan task update 1 author "new-author" -``` - -### Manage Parent-Child Relationships - -Update parent task: -```bash -# Set parent of task 2 to task 1 -agkan task update-parent 2 1 - -# Remove parent (orphan task 2) -agkan task update-parent 2 null -``` - -Notes: -- Deleting a parent task automatically removes the parent reference from child tasks (orphaning them) -- Circular references are automatically detected and prevented - -JSON output format: -```bash -agkan task update-parent 2 1 --json -``` - -```json -{ - "success": true, - "task": { - "id": 2, - "title": "Child Task", - "status": "backlog", - "body": null, - "author": null, - "parent_id": 1, - "created_at": "2026-02-15T00:00:00.000Z", - "updated_at": "2026-02-15T00:00:00.000Z" - }, - "parent": { - "id": 1, - "title": "Parent Task", - "status": "backlog", - "body": null, - "author": null, - "parent_id": null, - "created_at": "2026-02-15T00:00:00.000Z", - "updated_at": "2026-02-15T00:00:00.000Z" - } -} -``` - -### Manage Blocking Relationships - -Add blocking relationship (task 1 blocks task 2): -```bash -agkan task block add 1 2 -``` - -Remove blocking relationship: -```bash -agkan task block remove 1 2 -``` - -List blocking relationships: -```bash -# Show blocking relationships for task 1 -agkan task block list 1 -``` - -Notes: -- Circular references are automatically detected and prevented -- Blocking relationships are automatically deleted when a task is deleted (CASCADE DELETE) - -JSON output format: -```bash -agkan task block list 2 --json -``` - -```json -{ - "task": { - "id": 2, - "title": "API implementation", - "status": "backlog" - }, - "blockedBy": [ - { - "id": 1, - "title": "Database design", - "status": "in_progress" - } - ], - "blocking": [ - { - "id": 3, - "title": "Frontend implementation", - "status": "backlog" - } - ] -} -``` - -### Delete Tasks - -Delete a task: -```bash -agkan task delete 1 -``` - -### Manage Tags - -Create a tag: -```bash -agkan tag add "frontend" -``` - -List all tags: -```bash -agkan tag list -``` - -Delete a tag: -```bash -agkan tag delete "frontend" -``` - -JSON output format for tag list: -```bash -agkan tag list --json -``` - -```json -{ - "totalCount": 2, - "tags": [ - { - "id": 1, - "name": "frontend", - "taskCount": 3, - "created_at": "2026-02-15T00:00:00.000Z" - }, - { - "id": 2, - "name": "backend", - "taskCount": 1, - "created_at": "2026-02-15T00:00:00.000Z" - } - ] -} -``` - -### Attach Tags to Tasks - -Attach a tag to a task: -```bash -agkan tag attach 1 "frontend" -``` - -Or attach tags at creation time with `task add --tag`, instead of a separate `tag attach` call: -```bash -agkan task add "Implement login screen" --tag "frontend,urgent" -``` - -Remove a tag from a task: -```bash -agkan tag detach 1 "frontend" -``` - -Display tags on a task: -```bash -agkan tag show 1 -``` - -JSON output format for tag show: -```bash -agkan tag show 1 --json -``` - -```json -{ - "task": { - "id": 1, - "title": "Implement login screen", - "status": "in_progress" - }, - "tags": [ - { - "id": 1, - "name": "frontend", - "created_at": "2026-02-15T00:00:00.000Z" - }, - { - "id": 3, - "name": "urgent", - "created_at": "2026-02-15T00:00:00.000Z" - } - ] -} -``` - -### Manage Metadata - -Set metadata: -```bash -agkan task meta set 1 priority high -``` - -Get metadata: -```bash -agkan task meta get 1 priority -``` - -List all metadata: -```bash -agkan task meta list 1 -``` - -Delete metadata: -```bash -agkan task meta delete 1 priority -``` - -#### Priority (priority) - -Task priority is managed with the `priority` key: - -| Value | Meaning | -|-------|---------| -| `critical` | Requires immediate action. A blocking issue. | -| `high` | Should be addressed with priority | -| `medium` | Normal priority (default) | -| `low` | Address when time permits | - -### Count Tasks - -Display task count for all statuses: -```bash -agkan task count -``` - -Display task count for a specific status: -```bash -agkan task count --status in_progress -``` - -Script-friendly output (numbers only): -```bash -agkan task count -s in_progress -q -``` - -JSON output format for all statuses: -```bash -agkan task count --json -``` - -```json -{ - "total": 10, - "counts": { - "backlog": 3, - "ready": 2, - "in_progress": 4, - "done": 1, - "closed": 0 - } -} -``` - -JSON output format for specific status: -```bash -agkan task count --status in_progress --json -``` - -```json -{ - "status": "in_progress", - "count": 4 -} -``` - -### Kanban Board (Web UI) - -Start a local Kanban board viewer in your browser: ```bash agkan board ``` - -Specify a custom port: -```bash -agkan board -p 3000 ``` - -The board is served at `http://localhost:8080` by default. - -#### Claude Integration in the Board - -The board UI includes built-in Claude integration for running tasks directly from the browser: - -- **Run button**: Each task card has a "Run" button that launches `claude` for that task. A dropdown arrow next to the button also allows running in plan mode. -- **Plan button**: Runs `claude` in plan mode to generate a plan for the task without executing. -- **Stream modal**: When Claude is running, a modal window displays the live output stream in real time. A "Stop" button allows terminating the process. -- **Running indicator**: A header indicator shows when any Claude process is currently active. -- **Run Logs tab**: The task detail panel includes a "Run Logs" tab that shows the history of all past Claude executions for that task, with timestamps and full output. - -### Claude Process Status - -List currently executing Claude processes (requires the board server to be running): -```bash -agkan ps +Server is running on http://localhost:8080 ``` -Connect to a board server on a custom port: -```bash -agkan ps --port 3000 -``` - -This command queries the board server to show which Claude processes are currently running and which tasks they are associated with. - -JSON output format: -```bash -agkan ps --json -``` -```json -{ - "processes": [ - { - "taskId": 42, - "title": "Implement feature X", - "command": "claude" - } - ] -} -``` - -### Config - -Get resolved configuration values from `.agkan.yml` (defaults applied): - -```bash -agkan config get # Show full resolved config -agkan config get board.port # Show specific key (dot notation) -agkan config get --json # JSON output -``` - -Example output: -``` -✓ Resolved config - -path: /workspace/.agkan/data.db -board.port: 8080 -``` - -### Display Help - -Show command list: -```bash -agkan --help -``` - -Show task command help: -```bash -agkan task --help -``` - -Show help for specific command: -```bash -agkan task add --help -``` - -## JSON Output Format - -agkan supports machine-readable JSON output for 10 data retrieval and display commands. Add the `--json` flag to output structured data instead of human-readable text. - -### Supported Commands - -The following commands support JSON output: - -- `task add` - Create a new task -- `task list` - List tasks (with filtering) -- `task get` - Get task details -- `task find` - Search tasks by keyword -- `task count` - Count tasks by status -- `task update-parent` - Update parent-child relationship -- `task block list` - List blocking relationships -- `task tag list` - List all tags with task counts -- `task tag show` - Show tags for a specific task -- `task meta list` - List all metadata for a task -- `ps` - List currently executing Claude processes - -### Output Structure - -All JSON responses follow these patterns: - -**Success responses** include: -- Operation-specific data (task, tasks array, counts, etc.) -- Related data (parent, blockedBy, blocking, tags, etc.) -- Optional `success: true` field for write operations - -**Error responses** follow the format: -```json -{ - "success": false, - "error": { - "message": "Error description" - } -} -``` - -### Common Use Cases - -**1. Scripting and Automation** -```bash -# Get task count for CI/CD pipeline -TASK_COUNT=$(agkan task count --status backlog --json | jq '.counts.backlog') - -# Extract task IDs for processing -agkan task list --status ready --json | jq -r '.tasks[].id' -``` - -**2. Integration with Other Tools** -```bash -# Export tasks to external system -agkan task list --json | jq '.tasks' > tasks.json - -# Process blocking relationships -agkan task block list 1 --json | jq '.blockedBy[].title' -``` - -**3. Validation and Testing** -```bash -# Verify task creation -RESULT=$(agkan task add "Test" --json) -echo $RESULT | jq -e '.success == true' && echo "Success" -``` - -## Usage Examples - -### Hierarchical Task Management with Parent-Child Relationships - -Example of managing a project as a parent task with individual work items as children: - -```bash -# Create parent task -agkan task add "Website redesign" -# Output: Task created with ID: 1 - -# Create child tasks -agkan task add "Create design mockup" --parent 1 -agkan task add "Implement frontend" --parent 1 -agkan task add "Implement backend" --parent 1 - -# Display in tree format -agkan task list --tree -# Output: -# 1 [backlog] Website redesign -# ├─ 2 [backlog] Create design mockup -# ├─ 3 [backlog] Implement frontend -# └─ 4 [backlog] Implement backend - -# Display task details (including parent information) -agkan task get 2 -# Output: -# ID: 2 -# Title: Create design mockup -# Parent ID: 1 -# ... - -# Change parent -agkan task add "UI/UX improvements" -# Output: Task created with ID: 5 -agkan task update-parent 2 5 - -# Remove parent (orphan task) -agkan task update-parent 2 null -``` - -### Managing Dependencies with Blocking Relationships - -Example of explicitly managing task dependencies: - -```bash -# Create tasks -agkan task add "Database design" -# Output: Task created with ID: 1 - -agkan task add "API implementation" -# Output: Task created with ID: 2 - -agkan task add "Frontend implementation" -# Output: Task created with ID: 3 - -# Set blocking relationships (1 blocks 2, 2 blocks 3) -# Database design blocks API implementation -agkan task block add 1 2 - -# API implementation blocks Frontend implementation -agkan task block add 2 3 - -# Verify blocking relationships -agkan task block list 1 -# Output: -# Task 1 blocks: -# - Task 2 (API implementation) -# Task 1 is blocked by: -# (none) - -agkan task block list 2 -# Output: -# Task 2 blocks: -# - Task 3 (Frontend implementation) -# Task 2 is blocked by: -# - Task 1 (Database design) - -# Attempt circular reference (error) -agkan task block add 3 1 -# Output: Error: Circular reference detected +## Command Cheat Sheet -# Remove blocking relationship -agkan task block remove 1 2 -``` - -### Task Management with Tags - -Example of classifying tasks with tags: - -```bash -# Create tags -agkan tag add "frontend" -agkan tag add "backend" -agkan tag add "urgent" - -# Create tasks and attach tags -agkan task add "Implement login screen" -# Output: Task created with ID: 1 +| Command | Description | +|---|---| +| `agkan init` | Initialize `.agkan.yml` and the `.agkan/` data directory | +| `agkan task add [body]` | Create a task (`--status`, `--author`, `--parent`, `--tag`, `--file`, `--json`) | +| `agkan task list` | List tasks (`--tree`, `--root-only`, `--status`, `--author`, `--tag`, `--json`) | +| `agkan task find <keyword>` | Search tasks by title/body (`--all` includes done/closed) | +| `agkan task get <id>` | Show task details | +| `agkan task update <id> <field> <value>` | Update a task's status, title, body, or author | +| `agkan task update-parent <id> <parent-id>` | Set or clear (`null`) a task's parent | +| `agkan task delete <id>` | Delete a task | +| `agkan task block add\|remove\|list <id> [id2]` | Manage blocking relationships | +| `agkan task meta set\|get\|list\|delete <id> [key] [value]` | Manage task metadata (e.g. `priority`) | +| `agkan task count` | Count tasks by status | +| `agkan tag add\|list\|delete <name>` | Manage tags | +| `agkan tag attach\|detach\|show <task-id> <tag>` | Attach, detach, or list tags on a task | +| `agkan board` | Start the local Kanban board web UI | +| `agkan ps` | List currently running Claude processes | +| `agkan config get [key]` | Show resolved configuration values | +| `agkan --help` | Show all commands | -agkan tag attach 1 "frontend" -agkan tag attach 1 "urgent" +For full options, JSON output formats, and worked examples, see **[documentation/cli-reference.md](documentation/cli-reference.md)**. -agkan task add "API development" -# Output: Task created with ID: 2 +## Claude Code Integration -agkan tag attach 2 "backend" +agkan is designed to be driven by AI coding agents as well as humans: -# Or attach tags in the same command with --tag -agkan task add "Bug fix in payment flow" --tag "backend,urgent" -# Output: Task created with ID: 3 - -# Filter by tag -agkan task list --tag "frontend" -# Output: -# 1 [backlog] Implement login screen (tags: frontend, urgent) - -# Display task tags -agkan tag show 1 -# Output: -# Tags for task 1: -# - frontend -# - urgent - -# Remove a tag -agkan tag detach 1 "urgent" - -# Delete a tag (removes from all associated tasks) -agkan tag delete "urgent" -``` - -## Task Statuses - -- **icebox**: Frozen tasks not actively being considered (white display) -- **backlog**: Not yet started tasks (gray display) -- **ready**: Tasks ready to be started (blue display) -- **in_progress**: Tasks currently being worked on (yellow display) -- **review**: Tasks under review (cyan display) -- **done**: Completed tasks (green display) -- **closed**: Closed tasks (magenta display) +- **[agkan-skills](https://github.com/gendosu/agkan-skills)** — Claude Code skills for automated task execution, planning, and review +- **Run / Plan**: each task card in the board has a "Run" button that launches `claude` for that task, with a dropdown to run in plan mode instead +- **Stream modal**: while Claude is running, a modal shows the live output stream in real time, with a "Stop" button and a header indicator for active processes +- **Run Logs**: the task detail panel's "Run Logs" tab keeps the full history of past Claude executions, with timestamps and output ## Configuration -### Database Storage Location - -agkan allows customization of the database storage location via a configuration file. - -#### Configuration File: `.agkan.yml` - -Create a `.agkan.yml` file in your project root directory to specify the database storage location. - -**Configuration Example:** - -```yaml -# Path to database file -path: ./.agkan/data.db -``` - -#### Path Specification - -- **Relative Path**: Resolved relative to the current directory - ```yaml - path: ./data/kanban.db - path: ./.agkan/data.db - ``` - -- **Absolute Path**: Used as-is - ```yaml - path: /home/user/.config/akan/data.db - ``` - -#### Environment Variable Configuration - -agkan supports the `AGENT_KANBAN_DB_PATH` environment variable for specifying the database location. This is particularly useful in CI/CD environments and for managing multiple environments. - -**Setting the Environment Variable:** - -```bash -# Use a custom database path -export AGENT_KANBAN_DB_PATH=/path/to/your/database.db -agkan task list - -# Use absolute path -export AGENT_KANBAN_DB_PATH=/home/user/.config/akan/data.db - -# Use relative path -export AGENT_KANBAN_DB_PATH=./custom/location/data.db -``` - -**Priority Order:** - -The database path is resolved in the following priority order: - -**Normal Mode (when `NODE_ENV` is not `test`):** -1. **Environment Variable** (highest priority): `AGENT_KANBAN_DB_PATH` -2. **Configuration File** (fallback): `path` field in `.agkan.yml` -3. **Default Path** (lowest priority): `.agkan/data.db` - -**Test Mode (when `NODE_ENV=test`):** -1. **Environment Variable** (highest priority): `AGENT_KANBAN_DB_PATH` -2. **Configuration File** (fallback): `path` field in `.agkan-test.yml` -3. **Default Path** (lowest priority): `.agkan-test/data.db` - -**Test Mode Explanation:** - -Test mode (`NODE_ENV=test`) automatically isolates test data from production data: - -- Uses separate configuration file: `.agkan-test.yml` instead of `.agkan.yml` -- Uses separate default directory: `.agkan-test/` instead of `.agkan/` -- Environment variable still takes highest priority in test mode -- Prevents accidental mixing of test and production data - -**Use Cases:** - -1. **CI/CD Pipeline:** - ```bash - # Use temporary database for CI tests - export AGENT_KANBAN_DB_PATH=/tmp/ci-test-db.db - agkan task list - ``` - -2. **Multiple Environments:** - ```bash - # Development environment - export AGENT_KANBAN_DB_PATH=./dev/data.db - - # Staging environment - export AGENT_KANBAN_DB_PATH=./staging/data.db - - # Production environment - export AGENT_KANBAN_DB_PATH=./prod/data.db - ``` - -3. **Testing:** - ```bash - # Automated tests with isolated database - NODE_ENV=test pnpm test - # Uses .agkan-test/data.db by default - - # Override with custom test database - NODE_ENV=test AGENT_KANBAN_DB_PATH=/tmp/test.db pnpm test - ``` - -#### Default Behavior - -If no `.agkan.yml` file exists and no environment variable is set, the database is created in: - -``` -<current-directory>/.agkan/data.db -``` - -In test mode (`NODE_ENV=test`), the default location is: - -``` -<current-directory>/.agkan-test/data.db -``` - -#### Per-Project Management - -To manage separate tasks for different projects, place `.agkan.yml` in each project root: - -```bash -# Project A -cd /path/to/projectA -cat > .agkan.yml << EOF -path: ./.agkan/data.db -EOF - -# Project B -cd /path/to/projectB -cat > .agkan.yml << EOF -path: ./.agkan/data.db -EOF -``` - -This enables independent task management for each project. - -### Board Settings - -The `board` section in `.agkan.yml` allows you to customize the behavior of the `agkan board` command. - -#### Available Fields - -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `board.port` | number | `3000` | Port number for the board web server | -| `board.title` | string | `"agkan Board"` | Title displayed in the board UI | - -#### Configuration Example +Customize the database location and board via a `.agkan.yml` file in your project root: ```yaml -# Path to database file path: ./.agkan/data.db -# Board settings board: port: 8080 - title: "My Project Board" -``` - -#### Field Details - -- **`board.port`**: Specifies the TCP port on which the board web server listens. Useful when the default port `3000` is already in use. - ```yaml - board: - port: 8080 - ``` - -- **`board.title`**: Sets the title shown in the board UI. Helps distinguish boards when managing multiple projects. - ```yaml - board: - title: "My Project Board" - ``` - -### Models Settings - -The `models` section in `.agkan.yml` allows you to specify the Claude model and effort level used when executing planning and run commands via the board. - -#### Available Fields - -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `models.planning.model` | string | (Claude CLI default) | Model used for planning command execution | -| `models.planning.effort` | string | (Claude CLI default) | Effort level for planning command (`low`, `medium`, `high`, `xhigh`, `max`) | -| `models.run.model` | string | (Claude CLI default) | Model used for run/pr command execution | -| `models.run.effort` | string | (Claude CLI default) | Effort level for run/pr command (`low`, `medium`, `high`, `xhigh`, `max`) | - -Both full model names and Claude CLI aliases are supported. Both `model` and `effort` are optional within each entry. - -#### Configuration Example - -```yaml -# Database path -path: ./.agkan/data.db - -# Model settings -models: - planning: - model: claude-opus-4-7 - effort: high - run: - model: claude-sonnet-4-6 - effort: low -``` - -#### Using Aliases - -You can use short aliases instead of full model names: - -```yaml -models: - planning: - model: opus - effort: high - run: - model: sonnet -``` - -Supported aliases: `opus`, `sonnet`, `haiku` (resolved by the Claude CLI) - -#### Field Details - -- **`models.planning`**: Specifies the Claude model and effort level used when the board executes planning tasks. Recommended to use a high-capability model and effort level such as `opus` with `high`. - ```yaml - models: - planning: - model: opus - effort: high - ``` - -- **`models.run`**: Specifies the Claude model and effort level used when the board executes run or pr commands. The `pr` command also uses this value. - ```yaml - models: - run: - model: sonnet - effort: low - ``` - -### Permission Mode Settings - -The `permissionMode` field in `.agkan.yml` controls how Claude CLI permission checks are handled when executing tasks from the board. - -#### Available Values - -| Value | Claude CLI flag | Description | -|-------|----------------|-------------| -| (not set) | `--permission-mode auto` | Default. Claude uses auto permission mode | -| `auto` | `--permission-mode auto` | Claude uses auto permission mode | -| `bypassPermissions` | `--permission-mode bypassPermissions` | Bypass all permission checks | -| `acceptEdits` | `--permission-mode acceptEdits` | Automatically accept file edits | -| `dontAsk` | `--permission-mode dontAsk` | Do not ask for permissions | -| `plan` | `--permission-mode plan` | Plan-only mode | -| `default` | `--permission-mode default` | Claude default permission mode | -| `skipPermissions` | `--dangerously-skip-permissions` | Legacy flag (same as bypassing all checks) | - -#### Configuration Example - -```yaml -# Use auto permission mode (default) -permissionMode: auto - -# Use legacy --dangerously-skip-permissions flag -permissionMode: skipPermissions ``` -> **Breaking Change**: Prior to this feature, `--dangerously-skip-permissions` was always passed. The new default is `--permission-mode auto`. To restore the previous behavior, set `permissionMode: skipPermissions` in your `.agkan.yml`. - -## Planned Features +See **[documentation/configuration.md](documentation/configuration.md)** for the full reference, including environment variables, per-project setup, model selection, and permission modes. -### Task Attachments - -Task attachment management is currently under development. This feature will allow users to attach files to tasks for better context and documentation. - -**Planned CLI Commands:** -- `agkan task attach add <task-id> <file-path>` - Attach a file to a task -- `agkan task attach list <task-id>` - List all attachments for a task -- `agkan task attach delete <attachment-id>` - Remove an attachment from a task - -For detailed information about planned features, see [documentation/planned-features.md](documentation/planned-features.md). - -## Technology Stack - -- **Language**: TypeScript 5.x -- **CLI Framework**: Commander.js -- **Database**: SQLite3 (better-sqlite3) -- **Terminal Display**: Chalk -- **Web Server**: Hono (for Kanban board viewer) -- **Build Tool**: TypeScript Compiler - -## Project Structure - -See [documentation/project-structure.md](documentation/project-structure.md) for the full directory layout. - -## Database Schema - -See [documentation/database-schema.md](documentation/database-schema.md) for the full schema reference. - -## Development +## Task Statuses -See [documentation/development.md](documentation/development.md) for setup instructions, testing, and build information. +| Status | Meaning | +|---|---| +| `icebox` | Frozen, not actively being considered | +| `backlog` | Not yet started | +| `ready` | Ready to be started | +| `in_progress` | Currently being worked on | +| `review` | Under review | +| `done` | Completed | +| `closed` | Closed | + +## Documentation + +| Document | Description | +|---|---| +| [documentation/cli-reference.md](documentation/cli-reference.md) | Full command reference, options, and JSON output formats | +| [documentation/configuration.md](documentation/configuration.md) | `.agkan.yml` reference (paths, board, models, permission mode) | +| [documentation/project-structure.md](documentation/project-structure.md) | Repository directory layout | +| [documentation/database-schema.md](documentation/database-schema.md) | SQLite schema reference | +| [documentation/development.md](documentation/development.md) | Technology stack, local setup, and build information | +| [documentation/TESTING.md](documentation/TESTING.md) | Testing guide | +| [CONTRIBUTING.md](CONTRIBUTING.md) | How to contribute | +| [CHANGELOG.md](CHANGELOG.md) | Release history | ## License diff --git a/documentation/development.ja.md b/documentation/development.ja.md index 89b41e3f..0f92ae29 100644 --- a/documentation/development.ja.md +++ b/documentation/development.ja.md @@ -1,5 +1,14 @@ # 開発 +## 技術スタック + +- **言語**: TypeScript 5.x +- **CLIフレームワーク**: Commander.js +- **データベース**: SQLite3 (better-sqlite3) +- **ターミナル表示**: Chalk +- **Webサーバー**: Hono(カンバンボードビューア用) +- **ビルドツール**: TypeScript Compiler + ## 開発者向けセットアップ agkan自体の開発に参加したい開発者向けの手順: diff --git a/documentation/development.md b/documentation/development.md index 25dfb417..36b9c968 100644 --- a/documentation/development.md +++ b/documentation/development.md @@ -1,5 +1,14 @@ # Development +## Technology Stack + +- **Language**: TypeScript 5.x +- **CLI Framework**: Commander.js +- **Database**: SQLite3 (better-sqlite3) +- **Terminal Display**: Chalk +- **Web Server**: Hono (for Kanban board viewer) +- **Build Tool**: TypeScript Compiler + ## Developer Setup For contributors and developers who want to work on agkan itself: From 6b8d0095c4aa90eef8143be11024af5776f3e8e6 Mon Sep 17 00:00:00 2001 From: GENDOSU <gendosu@gmail.com> Date: Fri, 10 Jul 2026 15:31:27 +0000 Subject: [PATCH 5/6] docs: polish README.md/README.ja.md content and sync ja translation --- README.ja.md | 218 ++++++++++++++++++++++++++------------------------- README.md | 39 +++++++-- 2 files changed, 146 insertions(+), 111 deletions(-) diff --git a/README.ja.md b/README.ja.md index afe18b89..e42abdfd 100644 --- a/README.ja.md +++ b/README.ja.md @@ -3,183 +3,191 @@ [![Test](https://github.com/gendosu/agkan/workflows/Test/badge.svg?branch=main)](https://github.com/gendosu/agkan/actions/workflows/test.yml) [![Quality Check](https://github.com/gendosu/agkan/workflows/Quality%20Check/badge.svg?branch=main)](https://github.com/gendosu/agkan/actions/workflows/quality.yml) -TypeScriptで実装された軽量なCLIタスク管理ツールです。エージェント(AIアシスタント)との協働作業に最適化されています。 +TypeScriptで実装された軽量なCLIタスク管理ツールです。人間とAIコーディングエージェントが協働するために作られています。 -![agkan カンバンボード](docs/assets/readme-board.png) - -## 目次 - -- [特徴](#特徴) -- [クイックスタート](#クイックスタート) -- [コマンド早見表](#コマンド早見表) -- [Claude Code連携](#claude-code連携) -- [設定](#設定) -- [タスクステータス](#タスクステータス) -- [ドキュメント](#ドキュメント) -- [ライセンス](#ライセンス) +![agkanのカンバンボード](docs/assets/readme-board.png) ## 特徴 **タスク管理** -- シンプルで直感的なCLI。ステータスごとに色分けされた表示 -- SQLiteベースのローカルストレージ — サーバーやアカウント不要 -- 柔軟な入力: コマンドライン引数またはMarkdownファイルからタスクを作成 -- ステータス・作成者・タグでの絞り込み、キーワード検索 -- メタデータ: `priority` のようなキーバリューデータをタスクに付与 +- ローカルSQLiteで動く、シンプルで直感的なCLI +- 7つのステータスによるカンバンワークフロー: icebox, backlog, ready, in_progress, review, done, closed +- コマンドライン引数またはMarkdownファイルからタスクを作成。ステータス・作成者・タグで絞り込み +- ステータスごとに見やすい色分け表示 +- 構造化されたキー/バリュー形式のメタデータ(例: `priority`)をタスクごとに管理 **依存関係** -- ツリー表示対応の親子関係 -- タスク間のブロック関係。循環参照は自動検出 -- タグによるタスクの分類・検索 +- ツリー表示に対応した親子関係(`task list --tree`) +- 循環参照を自動検出するブロック関係 +- タスクを分類・検索するためのタグ機能 **カンバンボード** -- ローカルWebベースのカンバンボードビューア(`agkan board`) -- 7ステータスのワークフロー: icebox, backlog, ready, in_progress, review, done, closed +- ローカルで動く、設定不要のWeb UI(`agkan board`) +- ブラウザ上でステータス・タグ・作成者によるフィルタリングと閲覧 +- タスク詳細パネルで全履歴とClaude実行ログを確認可能 **AI連携** -- タスクカードから直接Claudeの実行・プランニングが可能。ライブ出力ストリーム付き -- タスクごとの過去のClaude実行履歴(Run Logs) -- Claude Code向けの補完パッケージ [agkan-skills](https://github.com/gendosu/agkan-skills) +- スクリプトや自動化に使える、主要コマンドの機械可読なJSON出力 +- Claude Code用の連携パッケージ [agkan-skills](https://github.com/gendosu/agkan-skills) +- ボードから直接Claudeを実行し、ライブストリーミング出力と実行履歴を確認可能 +- `agkan init` が登録するSessionStart hookにより、Claude Codeが毎セッション自動でagkanのコンテキストを読み込む ## クイックスタート -Node.js 20以上が必要です。 +以下の5ステップで、カンバンボードが動くところまで進めます。 + +### 1. インストール -**1. インストール** ```bash npm install -g agkan ``` -リポジトリから直接インストールすることもできます: `npm install -g https://github.com/gendosu/agkan.git` -**2. プロジェクトを初期化** +Node.js 20以上とnpmが必要です。GitHubから最新のコードを直接インストールする場合: +```bash +npm install -g https://github.com/gendosu/agkan.git +``` + +### 2. プロジェクトを初期化 + ```bash agkan init ``` ``` -✓ Created .agkan.yml -✓ Created .agkan/ +Created: .agkan.yml +Created: .agkan/ directory +Created: .claude/settings.local.json (added agkan SessionStart hook) ``` -これによりClaude CodeのSessionStart hookも登録され、セッション開始時に -最小限のagkan使用ガイドが自動でロードされます。Claude Codeを使わない場合は -無視して問題ありません。 -**3. タスクを作成** +### 3. タスクを作成 + ```bash -agkan task add "ログイン機能の実装" --status ready +agkan task add "Implement login feature" "Implement user authentication system" ``` ``` -Task created with ID: 1 +✓ Task created successfully + +ID: 1 +Title: Implement login feature +Status: backlog +Created: 2026/7/10 15:02:48 ``` -`--parent`、`--tag`、`--file` でさらにカスタマイズできます。 -**4. タスク一覧を表示** +### 4. タスク一覧を表示 + ```bash agkan task list ``` ``` -1 [ready] ログイン機能の実装 +Found 1 task(s): + +──────────────────────────────────────────────────────────────────────────────── + +[1] Implement login feature + Status: backlog + Priority: medium + Created: 2026/7/10 15:02:48 ``` -`--tree` で親子関係を含めて表示、`--status`/`--tag` で絞り込みができます。 -**5. カンバンボードを開く** +### 5. カンバンボードを開く + ```bash agkan board ``` ``` -Board running at http://localhost:8080 +Server is running on http://localhost:8080 ``` -ポートは `agkan board -p 3000` または `.agkan.yml` の `board.port` でカスタマイズできます。 + +別のポートを使いたい場合: `agkan board -p 3000` ## コマンド早見表 -全コマンドの一行サマリー: +各コマンドは `--help` でも使い方を確認できます。 | コマンド | 説明 | -|---------|------| -| `agkan init` | プロジェクトでagkanを初期化 | -| `agkan task add` | タスクを新規作成 | -| `agkan task list` | タスク一覧を表示(フィルタ付き) | -| `agkan task find` | キーワードでタスクを検索 | -| `agkan task get` | タスク詳細を表示 | -| `agkan task update` | タスクのステータス・タイトル・本文・作成者を更新 | -| `agkan task update-parent` | タスクの親を設定・解除 | -| `agkan task block add` | ブロック関係を追加 | -| `agkan task block remove` | ブロック関係を削除 | -| `agkan task block list` | タスクのブロック関係を一覧表示 | -| `agkan task delete` | タスクを削除 | -| `agkan tag add` | タグを作成 | -| `agkan tag list` | タグ一覧を表示 | -| `agkan tag delete` | タグを削除 | -| `agkan tag attach` | タスクにタグを付与 | -| `agkan tag detach` | タスクからタグを削除 | -| `agkan tag show` | タスクのタグを表示 | -| `agkan task meta set` | タスクにメタデータキーを設定 | -| `agkan task meta get` | タスクのメタデータ値を取得 | -| `agkan task meta list` | タスクの全メタデータを一覧表示 | -| `agkan task meta delete` | タスクからメタデータキーを削除 | -| `agkan task count` | ステータス別のタスク数をカウント | -| `agkan board` | ローカルカンバンボードビューアを起動 | +|---|---| +| `agkan init` | `.agkan.yml` と `.agkan/` データディレクトリを初期化 | +| `agkan task add <title> [body]` | タスクを作成(`--status`, `--author`, `--parent`, `--tag`, `--file`, `--json`) | +| `agkan task list` | タスク一覧を表示(`--tree`, `--root-only`, `--status`, `--author`, `--tag`, `--json`) | +| `agkan task find <keyword>` | タイトル・本文でタスクを検索(`--all` で done/closed も含める) | +| `agkan task get <id>` | タスク詳細を表示 | +| `agkan task update <id> <field> <value>` | タスクのstatus・title・body・authorを更新 | +| `agkan task update-parent <id> <parent-id>` | 親タスクを設定・解除(`null`) | +| `agkan task delete <id>` | タスクを削除 | +| `agkan task block add <id> <id2>` | `<id>` が `<id2>` をブロックする関係を追加 | +| `agkan task block remove <id> <id2>` | ブロック関係を削除 | +| `agkan task block list <id>` | ブロックしている/されているタスクを表示 | +| `agkan task meta set <id> <key> <value>` | タスクにメタデータを設定(例: `priority`) | +| `agkan task meta get <id> <key>` | タスクのメタデータを取得 | +| `agkan task meta list <id>` | タスクの全メタデータを一覧表示 | +| `agkan task meta delete <id> <key>` | タスクのメタデータを削除 | +| `agkan task count` | ステータス別のタスク数をカウント(`--status`, `--json`) | +| `agkan tag add <name>` | タグを作成 | +| `agkan tag list` | タスク数付きで全タグを一覧表示 | +| `agkan tag delete <name>` | タグを削除 | +| `agkan tag attach <task-id> <tag>` | タスクにタグを付与 | +| `agkan tag detach <task-id> <tag>` | タスクからタグを解除 | +| `agkan tag show <task-id>` | タスクに付与されたタグを一覧表示 | +| `agkan board` | ローカルのカンバンボードWeb UIを起動 | | `agkan ps` | 現在実行中のClaudeプロセスを一覧表示 | -| `agkan config get` | 解決済みの設定値を表示 | -| `agkan --help` | コマンドヘルプを表示 | +| `agkan config get [key]` | 解決済みの設定値を表示 | +| `agkan --help` | 全コマンドを表示 | -各コマンドは該当する箇所で`--json`による機械可読な出力に対応しており、上記の多くのコマンドには追加オプションもあります。全オプション一覧・JSON出力フォーマット・使用例は **[documentation/cli-reference.ja.md](documentation/cli-reference.ja.md)** を参照してください。 +全オプション・JSON出力フォーマット・具体的な使用例については **[documentation/cli-reference.ja.md](documentation/cli-reference.ja.md)** を参照してください。 ## Claude Code連携 -カンバンボードにはブラウザから直接Claudeを実行するための機能が組み込まれています: - -- **Run** — タスクに対して `claude` を起動。ボタン横のドロップダウンからプランモードでの実行も可能 -- **Plan** — 実行せずに計画のみを生成するプランモードで `claude` を起動 -- **ストリームモーダル** — 実行中のClaudeプロセスのライブ出力を表示。Stopボタンで終了可能 -- **実行中インジケーター** — Claudeプロセスが動作中の場合、ヘッダーにインジケーターを表示 -- **Run Logs** — タスク詳細パネルのタブに、過去のClaude実行履歴(タイムスタンプと全出力)を表示 +agkanは、人間だけでなくAIコーディングエージェントからも操作できるように設計されています: -自動でのタスク実行・プランニング・レビューのワークフローには、Claude Code向けの補完パッケージ **[agkan-skills](https://github.com/gendosu/agkan-skills)** をインストールしてください。 +- **[agkan-skills](https://github.com/gendosu/agkan-skills)** — タスクの自動実行・プランニング・レビューのためのClaude Codeスキル +- **Run / Plan**: ボードの各タスクカードには `claude` を起動する「Run」ボタンがあり、ドロップダウンからプランモードで実行することもできます +- **ストリームモーダル**: Claude実行中はモーダルにリアルタイムで出力が表示され、「Stop」ボタンと実行中インジケーターが利用できます +- **実行ログ**: タスク詳細パネルの「Run Logs」タブに、過去のClaude実行履歴(タイムスタンプと全出力)が保存されます +- **`agkan ps`**: 別のターミナルから、ボードが現在実行中のClaudeプロセスと、それが紐づくタスクを一覧表示できます ## 設定 -プロジェクトのルートに `.agkan.yml` を作成してagkanをカスタマイズします: +プロジェクトルートの `.agkan.yml` で、データベースの保存場所やボードをカスタマイズできます: ```yaml -# データベースファイルのパス path: ./.agkan/data.db -# ボード設定 board: port: 8080 ``` -データベースパスは `AGENT_KANBAN_DB_PATH` 環境変数でも上書きでき、`.agkan.yml` より優先されます。 +データベースパスは環境変数 `AGENT_KANBAN_DB_PATH` でも上書きでき、`.agkan.yml` より優先されます。 -`.agkan.yml` は以下もサポートしています: -- `models.planning` / `models.run` — ボードからplanning/runタスクを実行する際に使用するClaudeモデルとeffortレベル -- `permissionMode` — ボードからタスクを実行する際に渡されるClaude CLIのパーミッションフラグ +テストモード(`NODE_ENV=test`)では、`.agkan-test.yml` と `.agkan-test/` が自動的に使用され、テストが本番のタスクデータベースに影響しないよう分離されます。 -全フィールドリファレンス・パス解決の優先順位・テストモードの挙動については **[documentation/configuration.ja.md](documentation/configuration.ja.md)** を参照してください。 +プロジェクトごとの管理・モデル選択・パーミッションモードを含む全設定リファレンスは **[documentation/configuration.ja.md](documentation/configuration.ja.md)** を参照してください。 ## タスクステータス -| ステータス | 意味 | ボード表示色 | -|-----------|------|-------------| -| `icebox` | 積極的に検討していない凍結タスク | 白 | -| `backlog` | 未着手 | グレー | -| `ready` | 着手可能 | 青 | -| `in_progress` | 作業中 | 黄 | -| `review` | レビュー中 | シアン | -| `done` | 完了 | 緑 | -| `closed` | クローズ | マゼンタ | +タスクは以下の7つのステータスのいずれかで管理されます: + +| ステータス | 意味 | +|---|---| +| `icebox` | 積極的に検討していない凍結タスク | +| `backlog` | 未着手のタスク | +| `ready` | 着手可能なタスク | +| `in_progress` | 作業中のタスク | +| `review` | レビュー中のタスク | +| `done` | 完了したタスク | +| `closed` | クローズされたタスク | ## ドキュメント +詳細なリファレンスはこのファイルの外にあります: + | ドキュメント | 説明 | -|-------------|------| -| [documentation/cli-reference.ja.md](documentation/cli-reference.ja.md) | 全コマンドリファレンス・オプション・JSON出力フォーマット | -| [documentation/configuration.ja.md](documentation/configuration.ja.md) | `.agkan.yml` の全フィールドリファレンス | -| [documentation/database-schema.ja.md](documentation/database-schema.ja.md) | データベーススキーマリファレンス | -| [documentation/project-structure.ja.md](documentation/project-structure.ja.md) | ディレクトリ構成 | -| [documentation/development.ja.md](documentation/development.ja.md) | 開発者向けセットアップ・技術スタック・テスト・ビルド | -| [CONTRIBUTING.ja.md](CONTRIBUTING.ja.md) | コントリビューションガイドラインとTDDプラクティス | +|---|---| +| [documentation/cli-reference.ja.md](documentation/cli-reference.ja.md) | 全コマンドリファレンス、オプション、JSON出力フォーマット | +| [documentation/configuration.ja.md](documentation/configuration.ja.md) | `.agkan.yml` リファレンス(パス・ボード・モデル・パーミッションモード) | +| [documentation/project-structure.ja.md](documentation/project-structure.ja.md) | リポジトリのディレクトリ構成 | +| [documentation/database-schema.ja.md](documentation/database-schema.ja.md) | SQLiteスキーマリファレンス | +| [documentation/development.ja.md](documentation/development.ja.md) | 技術スタック、ローカルセットアップ、ビルド情報 | +| [documentation/TESTING.ja.md](documentation/TESTING.ja.md) | テストガイド | +| [CONTRIBUTING.ja.md](CONTRIBUTING.ja.md) | コントリビュート方法 | | [CHANGELOG.ja.md](CHANGELOG.ja.md) | リリース履歴 | ## ライセンス diff --git a/README.md b/README.md index 690fb72d..7127cf2f 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ A lightweight CLI task management tool, built for humans and AI coding agents wo - 7-status Kanban workflow: icebox, backlog, ready, in_progress, review, done, closed - Create tasks from CLI arguments or Markdown files; filter by status, author, or tag - Color-coded terminal output +- Metadata support (e.g. `priority`) for structured, per-task key/value fields **Dependencies** - Parent-child relationships with tree view (`task list --tree`) @@ -23,14 +24,18 @@ A lightweight CLI task management tool, built for humans and AI coding agents wo **Kanban Board** - Local, zero-config web UI (`agkan board`) - Filter and browse tasks by status, tag, or author in the browser +- Task detail panel with full task history and Claude run logs **AI Integration** - Machine-readable JSON output on key commands for scripting and automation - Companion [agkan-skills](https://github.com/gendosu/agkan-skills) package for Claude Code - Run Claude directly from the board, with live streaming output and run history +- `agkan init` installs a SessionStart hook so Claude Code loads agkan context automatically each session ## Quick Start +Go from zero to a running Kanban board in five steps. + ### 1. Install ```bash @@ -92,8 +97,12 @@ agkan board Server is running on http://localhost:8080 ``` +Need a different port? `agkan board -p 3000`. + ## Command Cheat Sheet +Every command also accepts `--help` for its own usage details. + | Command | Description | |---|---| | `agkan init` | Initialize `.agkan.yml` and the `.agkan/` data directory | @@ -104,11 +113,20 @@ Server is running on http://localhost:8080 | `agkan task update <id> <field> <value>` | Update a task's status, title, body, or author | | `agkan task update-parent <id> <parent-id>` | Set or clear (`null`) a task's parent | | `agkan task delete <id>` | Delete a task | -| `agkan task block add\|remove\|list <id> [id2]` | Manage blocking relationships | -| `agkan task meta set\|get\|list\|delete <id> [key] [value]` | Manage task metadata (e.g. `priority`) | -| `agkan task count` | Count tasks by status | -| `agkan tag add\|list\|delete <name>` | Manage tags | -| `agkan tag attach\|detach\|show <task-id> <tag>` | Attach, detach, or list tags on a task | +| `agkan task block add <id> <id2>` | Mark `<id>` as blocking `<id2>` | +| `agkan task block remove <id> <id2>` | Remove a blocking relationship | +| `agkan task block list <id>` | Show what a task blocks and is blocked by | +| `agkan task meta set <id> <key> <value>` | Set a metadata value on a task (e.g. `priority`) | +| `agkan task meta get <id> <key>` | Get a metadata value from a task | +| `agkan task meta list <id>` | List all metadata for a task | +| `agkan task meta delete <id> <key>` | Delete a metadata value from a task | +| `agkan task count` | Count tasks by status (`--status`, `--json`) | +| `agkan tag add <name>` | Create a tag | +| `agkan tag list` | List all tags with task counts | +| `agkan tag delete <name>` | Delete a tag | +| `agkan tag attach <task-id> <tag>` | Attach a tag to a task | +| `agkan tag detach <task-id> <tag>` | Detach a tag from a task | +| `agkan tag show <task-id>` | List tags attached to a task | | `agkan board` | Start the local Kanban board web UI | | `agkan ps` | List currently running Claude processes | | `agkan config get [key]` | Show resolved configuration values | @@ -124,6 +142,7 @@ agkan is designed to be driven by AI coding agents as well as humans: - **Run / Plan**: each task card in the board has a "Run" button that launches `claude` for that task, with a dropdown to run in plan mode instead - **Stream modal**: while Claude is running, a modal shows the live output stream in real time, with a "Stop" button and a header indicator for active processes - **Run Logs**: the task detail panel's "Run Logs" tab keeps the full history of past Claude executions, with timestamps and output +- **`agkan ps`**: from any terminal, list which Claude processes the board currently has running and which tasks they belong to ## Configuration @@ -136,10 +155,16 @@ board: port: 8080 ``` -See **[documentation/configuration.md](documentation/configuration.md)** for the full reference, including environment variables, per-project setup, model selection, and permission modes. +The database path can also be overridden with the `AGENT_KANBAN_DB_PATH` environment variable, which takes priority over `.agkan.yml`. + +In test mode (`NODE_ENV=test`), agkan automatically isolates data using `.agkan-test.yml` and `.agkan-test/` instead, so tests never touch your real task database. + +See **[documentation/configuration.md](documentation/configuration.md)** for the full reference, including per-project setup, model selection, and permission modes. ## Task Statuses +Every task moves through one of seven statuses: + | Status | Meaning | |---|---| | `icebox` | Frozen, not actively being considered | @@ -152,6 +177,8 @@ See **[documentation/configuration.md](documentation/configuration.md)** for the ## Documentation +Detailed reference material lives outside this file: + | Document | Description | |---|---| | [documentation/cli-reference.md](documentation/cli-reference.md) | Full command reference, options, and JSON output formats | From 3b8069968fd8e9e0775d8c14a4286c7940ff7e00 Mon Sep 17 00:00:00 2001 From: GENDOSU <gendosu@gmail.com> Date: Fri, 10 Jul 2026 23:30:43 +0000 Subject: [PATCH 6/6] docs: refine README tagline and remove outdated metadata feature Update project description in both English and Japanese to emphasize the integrated CLI & Kanban board capabilities. Remove outdated metadata feature mention that no longer reflects the current feature set. - README.md: Update tagline and feature list - README.ja.md: Sync Japanese translation with updated content Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --- README.ja.md | 3 +-- README.md | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/README.ja.md b/README.ja.md index e42abdfd..3f34ce4f 100644 --- a/README.ja.md +++ b/README.ja.md @@ -3,7 +3,7 @@ [![Test](https://github.com/gendosu/agkan/workflows/Test/badge.svg?branch=main)](https://github.com/gendosu/agkan/actions/workflows/test.yml) [![Quality Check](https://github.com/gendosu/agkan/workflows/Quality%20Check/badge.svg?branch=main)](https://github.com/gendosu/agkan/actions/workflows/quality.yml) -TypeScriptで実装された軽量なCLIタスク管理ツールです。人間とAIコーディングエージェントが協働するために作られています。 +人間とAIコーディングエージェントが一緒にタスクを進めるための、軽量なCLI&カンバンボードです。 ![agkanのカンバンボード](docs/assets/readme-board.png) @@ -14,7 +14,6 @@ TypeScriptで実装された軽量なCLIタスク管理ツールです。人間 - 7つのステータスによるカンバンワークフロー: icebox, backlog, ready, in_progress, review, done, closed - コマンドライン引数またはMarkdownファイルからタスクを作成。ステータス・作成者・タグで絞り込み - ステータスごとに見やすい色分け表示 -- 構造化されたキー/バリュー形式のメタデータ(例: `priority`)をタスクごとに管理 **依存関係** - ツリー表示に対応した親子関係(`task list --tree`) diff --git a/README.md b/README.md index 7127cf2f..e6b4b2e2 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Test](https://github.com/gendosu/agkan/workflows/Test/badge.svg?branch=main)](https://github.com/gendosu/agkan/actions/workflows/test.yml) [![Quality Check](https://github.com/gendosu/agkan/workflows/Quality%20Check/badge.svg?branch=main)](https://github.com/gendosu/agkan/actions/workflows/quality.yml) -A lightweight CLI task management tool, built for humans and AI coding agents working together. +A lightweight CLI & Kanban board for humans and AI coding agents to get things done together. ![agkan Kanban board](docs/assets/readme-board.png) @@ -14,7 +14,6 @@ A lightweight CLI task management tool, built for humans and AI coding agents wo - 7-status Kanban workflow: icebox, backlog, ready, in_progress, review, done, closed - Create tasks from CLI arguments or Markdown files; filter by status, author, or tag - Color-coded terminal output -- Metadata support (e.g. `priority`) for structured, per-task key/value fields **Dependencies** - Parent-child relationships with tree view (`task list --tree`)