taskflow
OpenClawエージェント向けに、マークダウンでの作成やSQLiteでのクエリ、双方向同期、CLI、Apple Notes連携などを通じて、構造化されたプロジェクトやタスクを管理するためのSkill。
📜 元の英語説明(参考)
Structured project/task management for OpenClaw agents — markdown-first authoring, SQLite-backed querying, bidirectional sync, CLI, Apple Notes integration.
🇯🇵 日本人クリエイター向け解説
OpenClawエージェント向けに、マークダウンでの作成やSQLiteでのクエリ、双方向同期、CLI、Apple Notes連携などを通じて、構造化されたプロジェクトやタスクを管理するためのSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o taskflow.zip https://jpskill.com/download/5461.zip && unzip -o taskflow.zip && rm taskflow.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/5461.zip -OutFile "$d\taskflow.zip"; Expand-Archive "$d\taskflow.zip" -DestinationPath $d -Force; ri "$d\taskflow.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
taskflow.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
taskflowフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-17
- 取得日時
- 2026-05-17
- 同梱ファイル
- 7
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
TaskFlow — エージェントスキルリファレンス
TaskFlow は、あらゆる OpenClaw エージェントに、Markdown ファーストのオーサリング、SQLite をバックエンドとするクエリ、双方向同期を備えた構造化されたプロジェクト/タスク/計画システムを提供します。
原則: Markdown が正典です。tasks/*.md を直接編集してください。SQLite DB は派生インデックスであり、真の情報源ではありません。
セキュリティ
OPENCLAW_WORKSPACE 信頼境界
OPENCLAW_WORKSPACE は高信頼値です。すべての TaskFlow スクリプトはここからファイルパスを解決し、CLI と同期デーモンはこれを使用して SQLite データベース、Markdown タスクファイル、およびログディレクトリを特定します。
安全な使用のためのルール:
-
信頼できる、管理されたソースからのみ設定してください。 値は以下から取得する必要があります。
- ご自身のシェルプロファイル (
.zshrc、.bashrc、/etc/environment) - ご自身で管理するテンプレート内の systemd ユーザーユニット
Environment=ディレクティブ - ご自身でインストールした macOS LaunchAgent
EnvironmentVariablesディクショナリ
決して
OPENCLAW_WORKSPACEを以下から受け入れないでください。- ユーザーが提供する CLI 引数または HTTP リクエストパラメータ
- 実行時に読み込まれる信頼できない設定ファイル
- 明示的に検証されていない外部入力
- ご自身のシェルプロファイル (
-
使用前にパスが存在することを確認してください。
OPENCLAW_WORKSPACEを読み取るスクリプトは、続行する前にディレクトリが存在することを確認する必要があります。import { existsSync } from 'node:fs' import path from 'node:path' const workspace = process.env.OPENCLAW_WORKSPACE if (!workspace) { console.error('OPENCLAW_WORKSPACE is not set. Aborting.') process.exit(1) } if (!existsSync(workspace)) { console.error(`OPENCLAW_WORKSPACE path does not exist: ${workspace}`) process.exit(1) } // 相対パスのトリックを無効にするため、絶対パスに解決します const safeWorkspace = path.resolve(workspace) -
信頼できない入力からパスを構築しないでください。 有効な
OPENCLAW_WORKSPACEがあっても、検証されていないユーザー入力をそれに連結しないでください (例:path.join(workspace, userSlug, '../../../etc/passwd'))。path.resolve()を使用し、解決されたパスがワークスペースルートで始まることを確認してください。function safeJoin(base, ...parts) { const resolved = path.resolve(base, ...parts) if (!resolved.startsWith(path.resolve(base) + path.sep)) { throw new Error(`Path traversal attempt detected: ${resolved}`) } return resolved } -
OPENCLAW_WORKSPACEはローカルシステムパスとしてのみ扱ってください。 ローカルファイルシステム上のディレクトリを指す必要があります。リモートパス (NFS マウント、ネットワーク共有) は機能する可能性がありますが、テスト済みの構成外であり、TOCTOU (time-of-check/time-of-use) 競合状態を引き起こす可能性があります。
セットアップ
1. 環境変数を設定する
シェルプロファイル (.zshrc、.bashrc など) に追加してください。
export OPENCLAW_WORKSPACE="/path/to/your/.openclaw/workspace"
すべての TaskFlow スクリプトと CLI は、この変数からパスを解決します。これがない場合、process.cwd() にフォールバックしますが、これはほとんどの場合、望ましいものではありません。
参照: セキュリティ要件については、上記の OPENCLAW_WORKSPACE 信頼境界 を参照してください。
2. CLI をリンクする
ln -sf {baseDir}/scripts/taskflow-cli.mjs /opt/homebrew/bin/taskflow # macOS (Apple Silicon)
# または: ln -sf {baseDir}/scripts/taskflow-cli.mjs /usr/local/bin/taskflow
3. セットアップウィザードを実行する
taskflow setup
ウィザードが残りの処理を行います。ワークスペースディレクトリを作成し、最初のプロジェクトの追加を案内し、データベースを初期化し、同期を行い、オプションで定期同期のための macOS LaunchAgent をインストールします。
代替 — 手動セットアップ:
<details> <summary>手動手順 (明示的な制御を好む場合)</summary>
# ワークスペースディレクトリを作成
mkdir -p "$OPENCLAW_WORKSPACE/tasks" "$OPENCLAW_WORKSPACE/plans" "$OPENCLAW_WORKSPACE/memory" "$OPENCLAW_WORKSPACE/logs"
# DB スキーマをブートストラップ
taskflow init
# PROJECTS.md と tasks/<slug>-tasks.md を手動で作成 (templates/ を参照)
# Markdown → DB を同期
taskflow sync files-to-db
# 確認
taskflow status
</details>
初回実行
エージェント (OpenClaw / AI) 向け
ユーザーが TaskFlow のセットアップを依頼した場合、または初期化されていないことを検出した場合:
- 状態を検出します。
$OPENCLAW_WORKSPACE/PROJECTS.mdと$OPENCLAW_WORKSPACE/memory/taskflow.sqliteを確認します。 - クリーンな状態の場合: ユーザーに最初のプロジェクト名と説明を尋ね、以下を実行します。
taskflow setup --name "Project Name" --desc "One-liner description"その後、
taskflow statusを実行して確認します。 - PROJECTS.md は存在するが DB がない場合:
taskflow setupを実行します (状態を自動的に検出し、初期化と同期を提案します)。 - 両方存在する場合:
taskflow statusを実行します — すでにセットアップ済みです。 - セットアップ後、
AGENTS.mdを新しいプロジェクトスラッグで更新し、将来のセッションでcat PROJECTS.mdを介して検出できるようにします。
人間 (CLI) 向け
taskflow setup
対話型ウィザードは以下を行います。
- 既存のワークスペース状態を検出します
- 最初のプロジェクトの名前付けを案内します
- テンプレートから
PROJECTS.mdとtasks/<slug>-tasks.mdを作成します - SQLite データベースを初期化し、同期します
- 自動 60 秒同期のための定期同期デーモン (macOS では LaunchAgent、Linux では systemd タイマー) のインストールを提案します
非対話型 (スクリプトによるインストール):
taskflow setup --name "My Project" --desc "What it does"
--name を渡すと、すべての対話型プロンプトがスキップされます (デーモンインストールも非対話型モードではスキップされます)。
ディレクトリレイアウト
<workspace>/
├── PROJECTS.md # プロジェクトレジストリ (プロジェクトごとに ## ブロックが1つ)
├── tasks/<slug>-tasks.md # プロジェクトごとのタスクリスト
├── plans/<slug>-plan.md # オプション: プロジェクトごとのアーキテクチャ/設計ドキュメント
└── taskflow/
├── SKILL.md # このファイル
├── scripts/
│ ├── taskflow-cli.mjs # CLI エントリポイント (シンボリックリンクターゲット)
│ ├── task-sync.mjs # 双方向 Markdown ↔ SQLite 同期
│ ├── init-db.mjs # SQLite スキーマのブートストラップ (冪等)
│ ├── export-projec 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
TaskFlow — Agent Skill Reference
TaskFlow gives any OpenClaw agent a structured project/task/plan system with markdown-first authoring, SQLite-backed querying, and bidirectional sync.
Principle: Markdown is canonical. Edit tasks/*.md directly. The SQLite DB is a derived index, not the source of truth.
Security
OPENCLAW_WORKSPACE Trust Boundary
OPENCLAW_WORKSPACE is a high-trust value. All TaskFlow scripts resolve file paths from it, and the CLI and sync daemon use it to locate the SQLite database, markdown task files, and log directory.
Rules for safe use:
-
Set it only from trusted, controlled sources. The value must come from:
- Your own shell profile (
.zshrc,.bashrc,/etc/environment) - The systemd user unit
Environment=directive in a template you control - The macOS LaunchAgent
EnvironmentVariablesdictionary you installed
Never accept
OPENCLAW_WORKSPACEfrom:- User-supplied CLI arguments or HTTP request parameters
- Untrusted config files read at runtime
- Any external input that has not been explicitly validated
- Your own shell profile (
-
Validate the path exists before use. Any script that reads
OPENCLAW_WORKSPACEshould confirm the directory exists before proceeding:import { existsSync } from 'node:fs' import path from 'node:path' const workspace = process.env.OPENCLAW_WORKSPACE if (!workspace) { console.error('OPENCLAW_WORKSPACE is not set. Aborting.') process.exit(1) } if (!existsSync(workspace)) { console.error(`OPENCLAW_WORKSPACE path does not exist: ${workspace}`) process.exit(1) } // Resolve to absolute path to neutralize any relative-path tricks const safeWorkspace = path.resolve(workspace) -
Do not construct paths from untrusted input. Even with a valid
OPENCLAW_WORKSPACE, never concatenate unvalidated user input onto it (e.g.path.join(workspace, userSlug, '../../../etc/passwd')). Usepath.resolve()and check that the resolved path starts with the workspace root:function safeJoin(base, ...parts) { const resolved = path.resolve(base, ...parts) if (!resolved.startsWith(path.resolve(base) + path.sep)) { throw new Error(`Path traversal attempt detected: ${resolved}`) } return resolved } -
Treat
OPENCLAW_WORKSPACEas a local system path only. It must point to a directory on the local filesystem. Remote paths (NFS mounts, network shares) may work but are outside the tested configuration and could introduce TOCTOU (time-of-check/time-of-use) race conditions.
Setup
1. Set environment variable
Add to your shell profile (.zshrc, .bashrc, etc.):
export OPENCLAW_WORKSPACE="/path/to/your/.openclaw/workspace"
All TaskFlow scripts and the CLI resolve paths from this variable. Without it, they fall back to process.cwd(), which is almost never what you want.
See also: OPENCLAW_WORKSPACE Trust Boundary above for security requirements.
2. Link the CLI
ln -sf {baseDir}/scripts/taskflow-cli.mjs /opt/homebrew/bin/taskflow # macOS (Apple Silicon)
# or: ln -sf {baseDir}/scripts/taskflow-cli.mjs /usr/local/bin/taskflow
3. Run the setup wizard
taskflow setup
The wizard handles the rest: creates workspace directories, walks you through adding your first project(s), initializes the database, syncs, and optionally installs the macOS LaunchAgent for periodic sync.
Alternative — manual setup:
<details> <summary>Manual steps (if you prefer explicit control)</summary>
# Create workspace dirs
mkdir -p "$OPENCLAW_WORKSPACE/tasks" "$OPENCLAW_WORKSPACE/plans" "$OPENCLAW_WORKSPACE/memory" "$OPENCLAW_WORKSPACE/logs"
# Bootstrap the DB schema
taskflow init
# Create PROJECTS.md and tasks/<slug>-tasks.md manually (see templates/)
# Sync markdown → DB
taskflow sync files-to-db
# Verify
taskflow status
</details>
First Run
For agents (OpenClaw / AI)
When a user asks you to set up TaskFlow or you detect it has not been initialized:
- Detect state. Check for
$OPENCLAW_WORKSPACE/PROJECTS.mdand$OPENCLAW_WORKSPACE/memory/taskflow.sqlite. - If clean slate: Ask the user for their first project name and description, then run:
taskflow setup --name "Project Name" --desc "One-liner description"Follow up by running
taskflow statusto confirm. - If PROJECTS.md exists but no DB: Run
taskflow setup(it detects the state automatically and offers to init + sync). - If both exist: Run
taskflow status— already set up. - After setup, update
AGENTS.mdwith the new project slug so future sessions discover it viacat PROJECTS.md.
For humans (CLI)
taskflow setup
The interactive wizard will:
- Detect your existing workspace state
- Walk you through naming your first project(s)
- Create
PROJECTS.mdandtasks/<slug>-tasks.mdfrom templates - Initialize the SQLite database and sync
- Offer to install the periodic-sync daemon (LaunchAgent on macOS, systemd timer on Linux) for automatic 60s sync
Non-interactive (scripted installs):
taskflow setup --name "My Project" --desc "What it does"
Passing --name skips all interactive prompts (daemon install is also skipped in non-interactive mode).
Directory Layout
<workspace>/
├── PROJECTS.md # Project registry (one ## block per project)
├── tasks/<slug>-tasks.md # Task list per project
├── plans/<slug>-plan.md # Optional: architecture/design doc per project
└── taskflow/
├── SKILL.md # This file
├── scripts/
│ ├── taskflow-cli.mjs # CLI entry point (symlink target)
│ ├── task-sync.mjs # Bidirectional markdown ↔ SQLite sync
│ ├── init-db.mjs # Bootstrap SQLite schema (idempotent)
│ ├── export-projects-overview.mjs # JSON export of project/task state
│ └── apple-notes-export.mjs # Optional: project state → Apple Notes (macOS only)
├── templates/ # Starter files for new projects
├── schema/
│ └── taskflow.sql # Full DDL
└── system/
├── com.taskflow.sync.plist.xml # Periodic sync (macOS LaunchAgent)
├── taskflow-sync.service # Periodic sync (Linux systemd user unit)
└── taskflow-sync.timer # Systemd timer (60s interval)
<workspace>/
└── taskflow.config.json # Apple Notes config (auto-created on first notes run)
Creating a Project
Follow this full checklist when creating a new project:
1. Add a block to PROJECTS.md
## <slug>
- Name: <Human-Readable Name>
- Status: active
- Description: One-sentence description of the project.
slugis lowercase, hyphenated (e.g.,my-project). It becomes the canonical project ID everywhere.- Valid status values:
active,paused,done.
2. Create the task file
Copy taskflow/templates/tasks-template.md → tasks/<slug>-tasks.md and update the project name in the heading.
The file must contain these five section headers in this order:
# <Project Name> — Tasks
## In Progress
## Pending Validation
## Backlog
## Blocked
## Done
3. Optionally create a plan file
Copy taskflow/templates/plan-template.md → plans/<slug>-plan.md for architecture docs, design decisions, and phased roadmaps. Plan files are not synced to SQLite — they are reference-only for the agent.
4. DB row (auto-created on first sync)
You do not need to manually insert into the projects table. The sync engine auto-creates the project row from PROJECTS.md on the next files-to-db run. If you want to be explicit via Node.js, use a parameterized statement:
// Safe: parameterized insert — no string interpolation in the SQL
db.prepare(`INSERT INTO projects (id, name, description, status)
VALUES (:id, :name, :description, 'active')`)
.run({ id: slug, name: projectName, description: projectDesc })
Task Line Format
Every task line follows this exact format:
- [x| ] (task:<id>) [<priority>] [<owner>] <title>
| Field | Details |
|---|---|
[ ] / [x] |
Open / completed. Sync drives status from section header, not this checkbox. |
(task:<id>) |
Task ID. Format: <slug>-NNN (zero-padded 3-digit). Sequential per project. |
[<priority>] |
Required. Must come before owner tag. See priority table below. |
[<owner>] |
Optional. Agent/model tag (e.g., codex, sonnet, claude). |
<title> |
Human-readable task title. |
⚠️ Tag Order Rule
Priority tag MUST come before owner tag. The sync parser is positional — it reads the first [Px] bracket as priority, and the next [tag] as owner. Swapping them will misparse the task.
⚠️ Title Sanitization Rules
Task titles must be plain text only. Before writing any user-supplied string as a task title, apply the following rules:
-
Reject lines that look like section headers. A title may not start with one or more
#characters followed by a space (e.g.# My heading,## Done). These would corrupt the sync parser's section detection. -
Reject the exact section header strings even without leading whitespace:
In Progress,Pending Validation,Backlog,Blocked,Done- Comparison must be case-insensitive.
-
Escape or strip markdown special characters that have structural meaning in the task file:
Character Risk Safe action #Looks like a header Strip or reject -(dash + space at line start)Looks like a list item / task Strip leading -[ ]/[x]Looks like a checkbox Escape brackets: \[\]]/[aloneCan corrupt (task:id)parseEscape: \[\]Newlines ( \n,\r)Creates multi-line titles Strip / reject -
Maximum length. Titles should be ≤ 200 characters. Truncate or reject longer strings.
Example sanitization (Node.js):
// Safe: sanitize a user-supplied task title before writing to markdown
function sanitizeTitle(raw) {
if (typeof raw !== 'string') throw new TypeError('title must be a string')
// Strip newlines
let title = raw.replace(/[\r\n]+/g, ' ').trim()
// Reject lines that look like section headers (# Heading or bare header words)
if (/^#{1,6}\s/.test(title)) {
throw new Error('Title may not start with a markdown heading (#)')
}
const BANNED_HEADERS = /^(in progress|pending validation|backlog|blocked|done)$/i
if (BANNED_HEADERS.test(title)) {
throw new Error('Title may not be a reserved section header name')
}
// Escape structural markdown characters
title = title
.replace(/\[/g, '\\[')
.replace(/\]/g, '\\]')
// Enforce length limit
if (title.length > 200) {
throw new Error('Title exceeds 200 character limit')
}
return title
}
These rules apply whenever a task title comes from any external or user-supplied source (CLI args, API payloads, file imports). Titles hard-coded by agents in their own sessions are low-risk but should still avoid structural characters.
✅ Correct: - [ ] (task:myproject-007) [P1] [codex] Implement search
❌ Wrong: - [ ] (task:myproject-007) [codex] [P1] Implement search
Priority Levels (Configurable)
| Tag | Default Meaning |
|---|---|
P0 |
Critical — must do now, blocks everything |
P1 |
High — important, do soon |
P2 |
Normal — standard priority (default) |
P3 |
Low — nice to have |
P9 |
Someday — no urgency, parking lot |
Priorities are configurable per-installation but the tags themselves (P0–P3, P9) are what the sync engine validates.
Optional Note Lines
A note can follow a task line as an indented - note: line:
- [ ] (task:myproject-003) [P1] [codex] Implement auth flow
- note: blocked on API key from vendor
Known limitation (v1): Notes are one-way. Removing or editing a note in markdown does not propagate to the DB. This is tracked for a post-MVP fix.
Example Task File Section
## In Progress
- [ ] (task:myproject-001) [P1] [codex] Wire up OAuth login
- note: PR open, needs review
## Backlog
- [ ] (task:myproject-002) [P2] Add rate limiting middleware
- [ ] (task:myproject-003) [P3] Write integration tests
Adding a New Task
-
Determine the next ID. Scan the task file for the highest existing
<slug>-NNNand increment by 1. Or query SQLite using a parameterized statement (never interpolate the slug into SQL strings):// Node.js — safe, parameterized const db = new DatabaseSync(dbPath) const row = db .prepare(`SELECT MAX(CAST(SUBSTR(id, LENGTH(:slug) + 2) AS INTEGER)) AS max_seq FROM tasks_v2 WHERE project_id = :slug`) .get({ slug: projectSlug }) const nextSeq = (row.max_seq ?? 0) + 1 const nextId = `${projectSlug}-${String(nextSeq).padStart(3, '0')}`⚠️ Never construct SQL by string interpolation. Use
db.prepare()with named or positional parameters (?or:name) for all values that come from external input. This applies even for read-only queries. -
Append the task line to the correct section (
## Backlogfor new work,## In Progressif starting immediately). -
Format the line using the exact format above. No trailing spaces. Priority tag before owner tag.
Updating Task Status
Move the task line from its current section to the target section in the markdown file.
| Target State | Move to Section |
|---|---|
| Started / picked up | ## In Progress |
| Needs human review | ## Pending Validation |
| Not started yet | ## Backlog |
| Waiting on dependency | ## Blocked |
| Finished | ## Done |
Also flip the checkbox: [ ] for active states, [x] for Done (and optionally Pending Validation).
The periodic sync (60s) will pick up the change and update SQLite automatically. To force an immediate sync:
node taskflow/scripts/task-sync.mjs files-to-db
Querying Tasks
Simple: Read the markdown file directly
cat tasks/<slug>-tasks.md
For a quick in-session view, just read the relevant section.
Advanced: Query SQLite
⚠️ SQL Safety Rule: Any query that incorporates a variable value (project slug, task ID, status string, etc.) must use parameterized statements — not string interpolation. The
sqlite3CLI examples below use only static, hardcoded literal values and are shown as diagnostic/inspection tools only. For programmatic use, always use the Node.jsdb.prepare()API with bound parameters.
sqlite3 CLI (static queries — for manual inspection only)
# All in-progress tasks across all projects (by priority)
# Safe: 'in_progress' is a static literal, not a variable
sqlite3 "$OPENCLAW_WORKSPACE/memory/taskflow.sqlite" \
"SELECT id, project_id, priority, title
FROM tasks_v2
WHERE status = 'in_progress'
ORDER BY priority, project_id;"
# Task count by status per project (no variables — safe for CLI)
sqlite3 "$OPENCLAW_WORKSPACE/memory/taskflow.sqlite" \
"SELECT project_id, status, COUNT(*) AS count
FROM tasks_v2
GROUP BY project_id, status
ORDER BY project_id, status;"
Do not embed shell variables directly in the SQL string (e.g.
WHERE project_id = '$SLUG'). That pattern is SQL injection waiting to happen. Use the Node.js API with parameters instead.
Node.js API — parameterized queries (required for programmatic use)
import { DatabaseSync } from 'node:sqlite'
import path from 'node:path'
const dbPath = path.join(process.env.OPENCLAW_WORKSPACE, 'memory', 'taskflow.sqlite')
const db = new DatabaseSync(dbPath)
db.exec('PRAGMA foreign_keys = ON')
// ── Backlog for a specific project ─────────────────────────────
// :slug is a named parameter — never interpolated into the SQL string
const backlog = db
.prepare(`SELECT id, priority, title
FROM tasks_v2
WHERE project_id = :slug AND status = 'backlog'
ORDER BY priority`)
.all({ slug: 'my-project' }) // value bound at runtime, never in SQL string
// ── Audit trail for a specific task ────────────────────────────
const transitions = db
.prepare(`SELECT from_status, to_status, actor, at
FROM task_transitions_v2
WHERE task_id = ?
ORDER BY at`)
.all('my-project-007') // positional parameter — also safe
// ── Write: update task status ───────────────────────────────────
// NEVER: db.exec(`UPDATE tasks_v2 SET status='${newStatus}' WHERE id='${id}'`)
// ALWAYS:
db.prepare(`UPDATE tasks_v2 SET status = :status, updated_at = datetime('now')
WHERE id = :id`)
.run({ status: 'done', id: 'my-project-007' })
CLI Quick Reference
# Terminal summary: all projects + task counts by status
taskflow status
# Add a task in markdown with automatic next ID
taskflow add taskflow "Implement quick add command" --priority P1 --owner codex
# List current tasks for a project (excludes done by default)
taskflow list taskflow
taskflow list --project "TaskFlow" --all
taskflow list task --status backlog,pending_validation --json
# JSON export of full project/task state (for dashboards, integrations)
node taskflow/scripts/export-projects-overview.mjs
# Detect drift between markdown and DB (exit 1 if mismatch)
node taskflow/scripts/task-sync.mjs check
# Sync markdown → DB (normal direction; run after editing task files)
node taskflow/scripts/task-sync.mjs files-to-db
# Sync DB → markdown (run after programmatic DB updates)
node taskflow/scripts/task-sync.mjs db-to-files
Apple Notes Export (Optional — macOS Only)
TaskFlow can maintain a live Apple Note with your current project status. The note is rendered as rich HTML and written via AppleScript.
# Push current status to Apple Notes (creates note on first run)
taskflow notes
On first run (or during taskflow setup), a new note is created in the configured folder and its Core Data ID is saved to:
$OPENCLAW_WORKSPACE/taskflow.config.json
Config schema:
{
"appleNotesId": "x-coredata://...",
"appleNotesFolder": "Notes",
"appleNotesTitle": "TaskFlow - Project Status"
}
Important — never delete the shared note. The note is always edited in-place. Deleting and recreating it generates a new Core Data ID and breaks any existing share links. If the note is accidentally deleted, taskflow notes will create a new one and update the config automatically.
For hourly auto-refresh, add a cron entry:
# Run: crontab -e
0 * * * * OPENCLAW_WORKSPACE=/path/to/workspace /path/to/node /path/to/taskflow/scripts/apple-notes-export.mjs
Or install a dedicated LaunchAgent (macOS) targeting apple-notes-export.mjs with an hourly StartInterval of 3600.
This feature is entirely optional and macOS-specific. On other platforms, taskflow notes exits gracefully with a message.
Memory Integration Rules
These rules keep daily memory logs clean and prevent duplication.
✅ Do
- Reference task IDs in daily memory logs when you complete or advance work:
Completed `myproject-007` (OAuth login). Moved `myproject-008` to In Progress. - Keep memory entries narrative — what happened, what you decided, what's next.
❌ Do Not
- Never duplicate the backlog in daily memory files.
tasks/<slug>-tasks.mdis the single source of truth for all pending work. Memory files should not list what's left to do. - Do not track task state changes in memory (e.g., "Task 007 is now in progress"). Only note meaningful progress events or decisions.
- Do not create new tasks in memory files. Add them to the task file directly.
Pattern: Loading Project Context
At the start of a session involving a project:
cat PROJECTS.md— identify the project slug and statuscat tasks/<slug>-tasks.md— load current task statecat plans/<slug>-plan.md— load architecture context (if it exists)- Begin work. Record task ID references in memory at session end.
Periodic Sync Daemon
The sync daemon runs task-sync.mjs files-to-db every 60 seconds in the background. This means markdown edits are automatically reflected in SQLite within a minute.
- Logs:
logs/taskflow-sync.stdout.logandlogs/taskflow-sync.stderr.log(relative to workspace) - Lock: Advisory TTL lock in
sync_statetable prevents concurrent syncs - Conflict resolution: Last-write-wins per sync direction
Quickest install (auto-detects OS)
taskflow install-daemon
This detects your platform and installs the appropriate unit. On macOS it installs and loads the LaunchAgent; on Linux it writes systemd user units and enables the timer.
macOS — LaunchAgent (manual steps)
Templates: taskflow/system/com.taskflow.sync.plist.xml
- Copy
taskflow/system/com.taskflow.sync.plist.xml→~/Library/LaunchAgents/com.taskflow.sync.plist - Replace
{{workspace}}with the absolute path to your workspace (no trailing slash) - Replace
{{node}}with the path to yournodebinary (which node) - Load:
launchctl load ~/Library/LaunchAgents/com.taskflow.sync.plist - Verify:
launchctl list | grep taskflow
Uninstall:
launchctl unload ~/Library/LaunchAgents/com.taskflow.sync.plist
rm ~/Library/LaunchAgents/com.taskflow.sync.plist
Linux — systemd user timer (manual steps)
Templates: taskflow/system/taskflow-sync.service and taskflow/system/taskflow-sync.timer
# Create the user unit directory
mkdir -p ~/.config/systemd/user
# Copy templates, replacing placeholders
sed -e "s|{{workspace}}|$OPENCLAW_WORKSPACE|g" \
-e "s|{{node}}|$(which node)|g" \
taskflow/system/taskflow-sync.service > ~/.config/systemd/user/taskflow-sync.service
sed -e "s|{{workspace}}|$OPENCLAW_WORKSPACE|g" \
-e "s|{{node}}|$(which node)|g" \
taskflow/system/taskflow-sync.timer > ~/.config/systemd/user/taskflow-sync.timer
# Enable and start
systemctl --user daemon-reload
systemctl --user enable --now taskflow-sync.timer
Verify:
systemctl --user status taskflow-sync.timer
journalctl --user -u taskflow-sync.service
Uninstall:
systemctl --user disable --now taskflow-sync.timer
rm ~/.config/systemd/user/taskflow-sync.{service,timer}
systemctl --user daemon-reload
Note: systemd user units require a login session. To run them without an interactive session (e.g. on a server), enable lingering:
loginctl enable-linger $USER
Section Header → DB Status Map
| Markdown Header | DB status value |
|---|---|
## In Progress |
in_progress |
## Pending Validation |
pending_validation |
## Backlog |
backlog |
## Blocked |
blocked |
## Done |
done |
Section headers are fixed. Do not rename them. The sync parser maps these exact strings.
Known Quirks
Things that work but might trip you up:
MAX(id)is lexicographic. Task IDs are text, soSELECT MAX(id)works only because IDs are zero-padded (-001,-002). If you create-1instead of-001, sequencing breaks. Always zero-pad to 3 digits.- Checkbox state is decorative. Status comes from which
##section a task lives under, not whether it's[x]or[ ]. The sync engine ignores the checkbox on read. On write-back,donetasks get[x], everything else gets[ ]. - Notes survive deletion. If you remove a
- note:line from markdown, the old note stays in the DB (COALESCE preserves it). This is intentional for v1 -- notes are one-way display. To truly clear a note, update the DB directly. - Lock TTL is 60 seconds. If a sync crashes without releasing the lock, the next run will be blocked for up to 60s. The SIGTERM/SIGINT handlers try to clean up, but a
kill -9won't. The lock auto-expires. - Auto-project creation derives names from slugs. If sync encounters a task file with no matching
projectsrow, it creates one with a name like "My Project" from slug "my-project". The name might not be what you want -- fix it in PROJECTS.md and re-sync. - Tag order is strict.
[P1] [codex]works.[codex] [P1]silently assignscodexas... nothing useful. Priority tag must come first.
Known Limitations (v1)
- Notes are one-way (markdown → DB). Removing a note in markdown does not clear it in DB.
db-to-filesrewrites all project task files, even unchanged ones.- One task file per project (1:1 mapping). Multiple files per project is post-MVP.
- Periodic sync daemon: macOS (LaunchAgent) and Linux (systemd user timer) are supported. Run
taskflow install-daemonto install. - Node.js 22.5+ required (
node:sqlite). No Python fallback in v1.
Quick Cheat Sheet
New project: PROJECTS.md block + tasks/<slug>-tasks.md + optional plans/<slug>-plan.md
New task: taskflow add <project> "title" (or append manually to section)
Update status: Move line to correct ## section, flip checkbox if needed
Query simple: cat tasks/<slug>-tasks.md
Query complex: Use db.prepare('SELECT ... WHERE id = ?').all(id) — never interpolate variables into SQL
CLI status: taskflow status
CLI add: taskflow add dashboard "Fix cron panel" --priority P1 --owner codex
Force sync: node taskflow/scripts/task-sync.mjs files-to-db
Memory rule: Reference IDs in logs; never copy backlog into memory 同梱ファイル
※ ZIPに含まれるファイル一覧。`SKILL.md` 本体に加え、参考資料・サンプル・スクリプトが入っている場合があります。
- 📄 SKILL.md (26,453 bytes)
- 📎 README.md (4,452 bytes)
- 📎 scripts/apple-notes-export.mjs (11,385 bytes)
- 📎 scripts/export-projects-overview.mjs (4,003 bytes)
- 📎 scripts/init-db.mjs (5,606 bytes)
- 📎 scripts/task-sync.mjs (13,192 bytes)
- 📎 scripts/taskflow-cli.mjs (45,107 bytes)