taskflow

GitHub 作者 LeoYeAI/openclaw-master-skills

Structured project/task management for OpenClaw agents — markdown-first authoring, SQLite-backed querying, bidirectional sync, CLI, Apple Notes integration.

安装 / 下载方式

TotalClaw CLI推荐
totalclaw install github:LeoYeAI~openclaw-master-skills~taskflow
cURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/github%3ALeoYeAI~openclaw-master-skills~taskflow/file -o taskflow.md
# 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:**

1. **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 `EnvironmentVariables` dictionary you installed

   **Never** accept `OPENCLAW_WORKSPACE` from:
   - User-supplied CLI arguments or HTTP request parameters
   - Untrusted config files read at runtime
   - Any external input that has not been explicitly validated

2. **Validate the path exists before use.** Any script that reads `OPENCLAW_WORKSPACE` should confirm the directory exists before proceeding:

   ```js
   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)
   ```

3. **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')`). Use `path.resolve()` and check that the resolved path starts with the workspace root:

   ```js
   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
   }
   ```

4. **Treat `OPENCLAW_WORKSPACE` as 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.):

```bash
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](#openclaw_workspace-trust-boundary) above for security requirements.

### 2. Link the CLI

```bash
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

```bash
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>

```bash
# 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:

1. **Detect state.** Check for `$OPENCLAW_WORKSPACE/PROJECTS.md` and `$OPENCLAW_WORKSPACE/memory/taskflow.sqlite`.
2. **If clean slate:** Ask the user for their first project name and description, then run:
   ```bash
   taskflow setup --name "Project Name" --desc "One-liner description"
   ```
   Follow up by running `taskflow status` to confirm.
3. **If PROJECTS.md exists but no DB:** Run `taskflow setup` (it detects the state automatically and offers to init + sync).
4. **If both exist:** Run `taskflow status` — already set up.
5. After setup, update `AGENTS.md` with the new project slug so future sessions discover it via `cat PROJECTS.md`.

### For humans (CLI)

```bash
taskflow setup
```

The interactive wizard will:
- Detect your existing workspace state
- Walk you through naming your first project(s)
- Create `PROJECTS.md` and `tasks/<slug>-tasks.md` from 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):**

```bash
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`

```markdown
## <slug>
- Name: <Human-Readable Name>
- Status: active
- Description: One-sentence description of the project.
```

- `slug` is 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:

```markdown
# <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:

```js
// Safe: parameterized insert — no string interpolation in the SQL
db.prepare(`INSERT INTO projec