{"id":49299683,"url":"https://github.com/satoh-y-0323/clade-parallel","last_synced_at":"2026-04-26T06:03:49.029Z","repository":{"id":352690805,"uuid":"1216215524","full_name":"satoh-y-0323/clade-parallel","owner":"satoh-y-0323","description":"Parallel execution wrapper for read-only Clade agents (Python)","archived":false,"fork":false,"pushed_at":"2026-04-20T17:34:18.000Z","size":266,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-20T19:32:21.608Z","etag":null,"topics":["claude","claude-code","cli","code-review","parallel-execution","python","subprocess"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/satoh-y-0323.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-20T17:25:50.000Z","updated_at":"2026-04-20T17:43:49.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/satoh-y-0323/clade-parallel","commit_stats":null,"previous_names":["satoh-y-0323/clade-parallel"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/satoh-y-0323/clade-parallel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/satoh-y-0323%2Fclade-parallel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/satoh-y-0323%2Fclade-parallel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/satoh-y-0323%2Fclade-parallel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/satoh-y-0323%2Fclade-parallel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/satoh-y-0323","download_url":"https://codeload.github.com/satoh-y-0323/clade-parallel/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/satoh-y-0323%2Fclade-parallel/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32287399,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-25T18:29:39.964Z","status":"online","status_checked_at":"2026-04-26T02:00:05.962Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["claude","claude-code","cli","code-review","parallel-execution","python","subprocess"],"created_at":"2026-04-26T06:03:47.376Z","updated_at":"2026-04-26T06:03:49.017Z","avatar_url":"https://github.com/satoh-y-0323.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# clade-parallel\n\n\u003e **Experimental / Alpha — v0.6**\n\u003e API and CLI are subject to change until v1.0.\n\nParallel execution wrapper for Clade agents (Python).\n\n## What this is\n\nClade is a framework composed of Markdown and natural language definitions.\nIt maintains a simple design that does not handle parallel execution by itself.\nWhen you need parallelism — for example, running multiple reviewers simultaneously —\n`clade-parallel` is an add-on wrapper you can layer on top.\n\n`clade-parallel`:\n\n- Reads a YAML-frontmatter Markdown manifest that declares tasks\n- Launches each task as a `claude -p` subprocess in parallel\n- Collects results and returns a summary with exit codes\n\nIt does **not** import Clade's code. The only contract is the manifest (a public data schema),\nso the coupling is minimal.\n\n## Requirements\n\n- Python 3.10+\n- `claude` CLI available on `PATH`\n- PyYAML (the only runtime dependency)\n\n## Installation\n\n```bash\npip install git+https://github.com/satoh-y-0323/clade-parallel.git\n```\n\n\u003e PyPI publication is planned for a future release.\n\nFor development (editable install with dev tools):\n\n```bash\ngit clone https://github.com/satoh-y-0323/clade-parallel.git\ncd clade-parallel\npip install -e \".[dev]\"\n```\n\n## Quick start\n\nRun the minimal hello demo to verify parallel execution works on your machine:\n\n```bash\nclade-parallel run examples/manifest-hello.md\n```\n\nEach task sends a simple question to `claude -p` in parallel and expects a short reply.\nBoth tasks should exit 0 within a few seconds (timeout is 120 s as a safety ceiling).\n\nTo run the full parallel-reviewer demo (requires Clade project context):\n\n```bash\nclade-parallel run examples/manifest.md\n```\n\n## Manifest format\n\nA manifest is a Markdown file with a YAML frontmatter block:\n\n```markdown\n---\nclade_plan_version: \"0.1\"\nname: \"my-plan\"\ntasks:\n  - id: task-one\n    agent: general-purpose\n    read_only: true\n    prompt: \"What is 2 + 2?\"\n    timeout_sec: 120\n  - id: task-two\n    agent: general-purpose\n    read_only: true\n    prompt: \"What is the capital of France?\"\n    timeout_sec: 120\n---\n\nAny Markdown content below the frontmatter is ignored by clade-parallel.\n```\n\n### Task fields\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `id` | Yes | Unique task identifier (used in output) |\n| `agent` | Yes | Agent type string passed to `claude -p` |\n| `read_only` | Yes | `true` (read-only) or `false` (write task; runs in an isolated worktree) |\n| `prompt` | No | Prompt string sent to the agent |\n| `timeout_sec` | No | Total task timeout in seconds (default: `900`). See [Timeout reference values](#timeout-reference-values) |\n| `idle_timeout_sec` | No | Idle (silent) timeout in seconds. Ignored for `read_only: true` tasks. See [Timeout reference values](#timeout-reference-values) |\n| `cwd` | No | Working directory for the subprocess (relative to the manifest file). Default: the manifest's directory |\n| `env` | No | Extra environment variables for the subprocess |\n| `writes` | No | List of file paths the task will write (used for static conflict detection) |\n| `depends_on` | No | List of task IDs that must complete before this task starts |\n| `max_retries` | No | `int`, default `0`. Maximum number of additional attempts after the first failure. `0` = no retries. Timeouts and permanent failures (rate limit, permission denied, etc.) are not retried. |\n\n### Timeout reference values\n\nChoosing appropriate `timeout_sec` and `idle_timeout_sec` depends on the scale\nof the task. The table below shows reference values by development scale.\nValues should be adjusted based on actual measurements in your environment.\n\n| Scale | File count / lines | `timeout_sec` (developer) | `idle_timeout_sec` (developer) | `timeout_sec` (reviewer) |\n|---|---|---|---|---|\n| **Small** (default) | ~10 files / hundreds of lines | 900 (15 min) | 600 (10 min) | 900 (15 min) |\n| **Medium** | 10–50 files / thousands of lines | 1800 (30 min) | 900 (15 min) | 1800 (30 min) |\n| **Large** | 50+ files / tens of thousands of lines | 3600 (1 h) | 1200 (20 min) | 9000 (2.5 h) |\n\n**Notes:**\n\n- Defaults (`timeout_sec: 900`, no `idle_timeout_sec`) target small-scale development.\n- A fixed startup cost of 60–120 seconds (worktree creation + `claude` launch) is\n  incurred for each task. Set `idle_timeout_sec` to at least **300 seconds** so this\n  silent startup phase does not trigger a false idle timeout.\n- `idle_timeout_sec` is automatically ignored for `read_only: true` tasks\n  (reviewer agents enter a silent synthesis phase after reading files; see\n  `runner.py` `effective_idle_timeout`).\n- For production use, measure actual task duration once and set\n  `timeout_sec ≈ observed maximum × 1.5` as a safety margin.\n\n### `depends_on` — task dependencies\n\nTasks that declare `depends_on` will not start until all listed tasks have completed successfully.\nIf any dependency fails, the dependent task is **skipped** (not executed).\nSkipped tasks propagate transitively: if B depends on A and A fails, B is skipped; if C depends on B, C is also skipped.\nTasks with no dependencies (or with all dependencies satisfied) run in parallel.\n\n```markdown\n---\nclade_plan_version: \"0.2\"\nname: \"sequential-example\"\ntasks:\n  - id: fetch\n    agent: general-purpose\n    read_only: true\n    prompt: \"Fetch the data\"\n  - id: process\n    agent: general-purpose\n    read_only: true\n    prompt: \"Process the data\"\n    depends_on:\n      - fetch\n  - id: report\n    agent: general-purpose\n    read_only: true\n    prompt: \"Summarize results\"\n    depends_on:\n      - process\n---\n```\n\nCircular dependencies and references to undefined task IDs are detected at parse time and raise a `ManifestError`.\n\n### `read_only: false` — write tasks with worktree isolation\n\nTasks with `read_only: false` are executed inside an isolated `git worktree`\n(`\u003cgit_root\u003e/.clade-worktrees/\u003ctask_id\u003e-\u003cuuid8\u003e/`).\nEach write task gets its own directory, so parallel write tasks cannot overwrite each other's files.\n\n**Requirement**: the manifest must be run from within a git repository when any task has `read_only: false`.\nRunning outside a git repository raises a `RunnerError`.\nManifests with all tasks set to `read_only: true` continue to work outside git repositories (backward compatible).\n\nThe worktree directory is created before the task starts and removed after the task finishes (success or failure).\nCleanup failures are silently ignored to avoid masking the actual task result.\n\n```markdown\n---\nclade_plan_version: \"0.2\"\nname: \"write-example\"\ntasks:\n  - id: writer\n    agent: general-purpose\n    read_only: false\n    prompt: \"Write a summary to output.md\"\n    writes:\n      - output.md\n---\n```\n\n### Manifest version history\n\n| `clade_plan_version` | Notable additions |\n|----------------------|-------------------|\n| `\"0.1\"` | Initial release |\n| `\"0.2\"` | `writes:` declarations + static conflict checks |\n| `\"0.3\"` | `depends_on:` DAG scheduler + worktree isolation for write tasks |\n| `\"0.4\"` | `max_retries` field (automatic retry on transient failures) |\n\nAll versions from `0.1` through `0.4` are accepted. Older manifests without\n`clade_plan_version` default to `\"0.1\"` behavior.\n\n## CLI options\n\n```bash\nclade-parallel run \u003cmanifest\u003e                       # Run all tasks\nclade-parallel run \u003cmanifest\u003e --max-workers 2        # Limit parallelism\nclade-parallel run \u003cmanifest\u003e --claude-exe /path/to/claude  # Custom binary\nclade-parallel run \u003cmanifest\u003e --quiet                # Summary only (suppress per-task output)\nclade-parallel run \u003cmanifest\u003e --log-dir PATH         # Directory for per-task stdout/stderr logs (default: \u003cgit-root\u003e/.claude/logs)\nclade-parallel run \u003cmanifest\u003e --no-log               # Disable per-task log file persistence\nclade-parallel --version\nclade-parallel --help\n```\n\n### Timeout output (tail display)\n\nWhen a task times out (either `timeout_sec` or `idle_timeout_sec`), clade-parallel\nprints the last 20 lines of the task's stdout to **stderr** before reporting the\nresult. This helps diagnose what the agent was doing at the moment of the timeout.\n\n```\n[timeout] my-task (general-purpose) duration=300.12 returncode=None (total timeout)\n  Last 20 lines before timeout:\n  \u003e ...\n  \u003e ...\n```\n\n**Important notes:**\n\n- The tail is always displayed for timed-out tasks, even when `--quiet` is specified.\n  (`--quiet` suppresses output only for successful tasks; timeouts are never considered\n  successful.)\n- The tail output goes to **stderr**, so it is not included when you redirect stdout\n  (e.g., `clade-parallel run manifest.md \u003e output.txt`).\n- **CI environments**: Agent stdout may contain sensitive information such as API keys,\n  authentication tokens, or file contents read by the agent. If your CI job logs are\n  publicly visible (e.g., open-source GitHub Actions), ensure that no secrets appear in\n  agent output, or configure your CI to mask sensitive values before they reach the log.\n  There is currently no `--no-tail` flag; if you need to suppress this output entirely,\n  redirect stderr to `/dev/null` (`2\u003e/dev/null`).\n\n## Automatic retry\n\nAdd `max_retries: N` to any task to automatically retry it up to `N` additional times\non transient failures. The default is `0` (no retries).\n\n```markdown\n---\nclade_plan_version: \"0.4\"\nname: \"retry-example\"\ntasks:\n  - id: flaky-task\n    agent: general-purpose\n    read_only: true\n    prompt: \"Do something that might transiently fail\"\n    timeout_sec: 300\n    max_retries: 2\n---\n```\n\n**Failure classification:**\n\nclade-parallel classifies each failure into a `failure_category` before deciding whether to retry:\n\n| `failure_category` | Meaning | Retried? |\n|--------------------|---------|----------|\n| `\"none\"` | Success | — |\n| `\"transient\"` | Temporary error (e.g., network blip, unknown non-zero exit) | Yes, up to `max_retries` times |\n| `\"permanent\"` | Unrecoverable error (rate limit, permission denied, authentication failure, etc.) | No — short-circuits immediately |\n| `\"timeout\"` | Task exceeded `timeout_sec` or `idle_timeout_sec` | No — short-circuits immediately |\n\n**Notes:**\n\n- `failure_category` and `retry_count` are included in the `TaskResult` and shown in the CLI summary.\n- Each attempt counts toward the task's own `timeout_sec` independently; there is no global retry budget.\n- Negative or non-integer values for `max_retries` raise a `ManifestError` at parse time.\n- A reasonable upper bound is 3–5 retries. Very large values (e.g. \u003e 10) can\n  waste significant token budget if the failure is systemic rather than transient.\n\n## Task logs\n\nBy default, clade-parallel saves the stdout and stderr of every task to:\n\n```\n\u003cgit-root\u003e/.claude/logs/\u003ctask_id\u003e-stdout.log\n\u003cgit-root\u003e/.claude/logs/\u003ctask_id\u003e-stderr.log\n```\n\nWhen a task is retried, subsequent attempts are **appended** to the same file with a separator:\n\n```\n===== retry attempt 1 =====\n\u003coutput of retry attempt 1\u003e\n```\n\n**CLI options:**\n\n- `--no-log`: Disable log file persistence entirely.\n- `--log-dir PATH`: Override the default log directory.\n\n**Recommended `.gitignore` entry:**\n\n```gitignore\n/.claude/logs/\n```\n\n\u003e **Security note**: Task logs may contain sensitive information such as API\n\u003e keys or credentials that appear in stderr output. The `.claude/logs/`\n\u003e directory is excluded from git by default (add `/.claude/logs/` to\n\u003e `.gitignore`), but avoid uploading logs as CI artefacts or sharing them\n\u003e publicly. Use `--no-log` to disable log persistence when running in\n\u003e sensitive environments.\n\n## Exit codes\n\n| Code | Meaning |\n|------|---------|\n| 0 | All tasks succeeded |\n| 1 | One or more tasks failed |\n| 2 | ManifestError (invalid manifest format) |\n| 3 | RunnerError (e.g., `claude` binary not found) |\n\n## Known limitations\n\n- **`/agent-*` (Clade slash commands) in `-p` mode**: Clade's `/agent-*` slash commands\n  are designed for interactive use with Q\u0026A and approval dialogs. In `claude -p`\n  (non-interactive) mode they may not reach the report-generation step as intended.\n  Workaround: use direct `Agent` tool invocations with `subagent_type` in the prompt\n  (see `examples/manifest.md`).\n\n- **Write tasks require a git repository**: Tasks with `read_only: false` must be run\n  from within a git repository (worktree isolation relies on `git worktree add`).\n  Manifests with only `read_only: true` tasks still work outside git repositories.\n\n- **Sensitive file warnings in `claude -p` mode**: When a task's working\n  directory contains `.env` files, SSH private keys, or other sensitive\n  files, `claude -p` emits a sensitive-file warning and the agent may\n  terminate before producing output. Workaround: run tasks in a working\n  directory that does not contain such files (e.g., point `cwd` at a\n  clean subdirectory), or add the files to `.gitignore` / move them\n  outside the repository root before running clade-parallel. Write tasks\n  (`read_only: false`) run in an isolated worktree and are less affected\n  by this issue.\n\n- **`writes:` の静的チェックはシンボリックリンクの実行時差し替えを保護しない**: `writes:` による衝突検出はマニフェストのパース時点でパスを解決して比較します。エージェントが実行時にシンボリックリンクを新たに作成・差し替えた場合、静的チェックでは検知できません。\n\n- **`env` block-list**: The following keys are silently rejected from `task.env` for\n  security reasons: `LD_PRELOAD`, `LD_LIBRARY_PATH`, `LD_AUDIT`,\n  `DYLD_INSERT_LIBRARIES`, `DYLD_LIBRARY_PATH`, `PYTHONPATH`.\n\n## Development\n\n```bash\ngit clone https://github.com/satoh-y-0323/clade-parallel.git\ncd clade-parallel\npip install -e \".[dev]\"\npytest\n```\n\nLinting and type checks:\n\n```bash\nruff check src/ tests/\nblack --check src/ tests/\nmypy src/ tests/\n```\n\n### Pre-commit hooks\n\nTo run linting and type checks automatically on every commit, install the hooks\n(`pre-commit` is included in `.[dev]`):\n\n```bash\npre-commit install\n```\n\nAfter installation, the hooks run automatically on `git commit`. To run them manually against all files:\n\n```bash\npre-commit run --all-files\n```\n\n\u003e **Keeping hook versions in sync:** The `rev:` values in `.pre-commit-config.yaml`\n\u003e are pinned to specific tool versions. When you upgrade `black`, `ruff`, or `mypy`\n\u003e in your development environment, update the corresponding `rev:` as well.\n\u003e Run `pip show black ruff mypy` to check your installed versions before updating.\n\n## Roadmap\n\n| Version | Focus | Status |\n|---------|-------|--------|\n| v0.2 | `writes:` declarations + static conflict checks | Released |\n| v0.3 | `depends_on:` DAG scheduler + worktree isolation for write tasks | Released |\n| v0.5 | Progress display, dual timeout (`idle_timeout_sec`), startup phase display | Released |\n| v0.6 | Automatic retry (`max_retries`), per-task log persistence (`--log-dir` / `--no-log`) | In progress |\n| v0.7+ | Partial re-run / telemetry | Planned |\n\n## License\n\nMIT © 2026 satoh-y-0323\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsatoh-y-0323%2Fclade-parallel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsatoh-y-0323%2Fclade-parallel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsatoh-y-0323%2Fclade-parallel/lists"}