Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

- Optional `local-image-gen` sidecar discovery: `dyro doctor` reports PATH
presence only, and `dyro image doctor` / `dyro image install` stay off the
coding-tool catalog and Skill seats. Dyro still does not generate images.

## 0.7.4 - 2026-08-18

- First-party Skill seats now include `dyro-executor` and `dyro-board` beside
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,8 @@ Install recipes are built into Dyro as shell-free argv. Project files cannot
supply install commands. Remote-script installers are never executed by Dyro;
after confirmation it opens the official page instead. See
[coding-tool catalog and guided installation](docs/tool-catalog.md).
The optional [image sidecar](docs/image-sidecar.md) is a separate CLI
(`local-image-gen`), not a home tool and not a managed seat.
An OpenClaw workspace is a default working directory, not an operating-system
sandbox; the onboarding prompt calls out that boundary before launch.

Expand Down Expand Up @@ -612,20 +614,29 @@ dyro --dry-run task run API-101
| `blueprint validate` / `join` | Validate a team-owned generic blueprint and create a resumable isolated multi-repository workspace. |
| `setup` / `init --discover` / `init --wizard` / `repo add/list` / `bootstrap` / `start` | Onboard a teammate without TOML edits, manage anchors, and choose a line and agent. |
| `doctor` / `status` / `status --all` | Validate and display one or every registered workspace. |
| `next` | Print the one safe follow-up. A live Objective may emit `tick` or `attention`; `next.commands` stays empty. |
| `image doctor` / `image install` | Discover or guide-install the optional `local-image-gen` sidecar. Does not generate images. |
| `line create/list` | Create, register, and inspect feature development lines. |
| `hotfix create` | Create a hotfix line from an explicit production base. |
| `changeset create/list/verify` | Pin and verify the exact clean Git heads that make up a multi-repository delivery. |
| `objective list/status/explain/tick/attention/plan` | Inspect accepted Objectives and the switch-tool briefing. Mutations stay on `objective apply`. |
| `proof list/show/verify/export/verify-bundle` | Rebind delivery Proof. `verify` rebinds the workspace; `verify-bundle` checks portable integrity only. `live` is not merge. |
| `config get/set` / `agent list/add/test/discover` / `tool list/install/default/pin` / `open` | Safely manage policy, adapters, tool discovery and personal launch preferences, or open an agent in the correct line. |
| `integration status/install/sync/uninstall` | Manage first-party Skill seats (`dyro-control-plane`, `dyro-executor`, `dyro-board`, `dyro-dispatch`). Loading a seat is not consent to mutate. |
| `task create/open/list/board/status/next/graph/explain/attempts/binding` | Create or enter tasks, manage state, validate the task graph, explain scheduling, inspect provenance, and output review bindings. |
| `task run/answer/gates/review/signoff` | Run tasks, resolve questions, execute gates, request independent review, and record external sign-off when a Profile requires it. |
| `task claim --output` / `task evidence build/execution/review` | One-time claim with a create-only runner handoff file, portable execution-evidence build/import, and receipt-bound review import. |
| `task merge` | Merge a reviewed task branch into its owning development line. |
| `task loop/daemon/stats/decisions` | Run controlled batches, scheduling, ledger reporting, and decision gates. |
| `dispatch` | Optional local multi-agent dispatch (L0–L4); advisory only — not a substitute for gates/merge. |

First-party seats are installed with `dyro integration`. Proof is rebound with
`dyro proof verify`; it does not replay gates.

See the [architecture and Profile contract](docs/architecture.md),
the [workspace blueprint contract](docs/workspace-blueprints.md),
the [existing control-plane migration guide](docs/migrating-existing-control-planes.md),
the [optional image sidecar](docs/image-sidecar.md),
and the [PyPI publishing runbook](docs/publishing.md) (maintainers) for implementation detail.

## Languages and documentation
Expand All @@ -639,3 +650,7 @@ DyroEngineeringFlow provides a complete local workflow loop and policy controls
### Graph Engineering (optional reading)

Some discussions call multi-node agent/work topologies **Graph Engineering** (as opposed to a single-agent loop). Dyro’s delivery topology is close in substance—TaskGraph, state machine, gates, review, merge, plus the optional `dispatch` subgraph—but the product identity remains a **delivery control plane**, not an agent-orchestration framework or a knowledge-graph/RAG stack. Dispatch output is advisory. See [architecture](docs/architecture.md#与-graph-engineering-的关系可选读).

## Related sibling

[`local-image-gen`](https://github.com/DandreYang/local-image-gen) is an optional first-party image CLI. Same house, not the same product: it is not a Dyro coding tool and not a managed Skill seat. Installing Dyro does not install it. See the [image sidecar](docs/image-sidecar.md).
15 changes: 14 additions & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,8 @@ dyro tool install openclaw
安装配方是 Dyro 内置的无 shell argv,项目文件不能提供安装命令。对于需要执行
远程脚本的官方安装方式,Dyro 不会代为执行,只会在确认后打开官方页面。详见
[编码工具目录与安装引导](docs/tool-catalog.md)。
可选的[生图 sidecar](docs/image-sidecar.md) 是独立 CLI(`local-image-gen`),
不是首页编码工具,也不是托管座位。
OpenClaw 工作区是默认工作目录,并不是操作系统级沙箱;初始化前会明确提示这一边界。

也可以显式登记、切换和查看所有项目;这些命令只管理全局入口,不会移动或删除项目:
Expand Down Expand Up @@ -550,18 +552,25 @@ dyro --dry-run task run API-101
| `blueprint validate` / `join` | 验证团队自有的通用蓝图,并创建可续跑的隔离多仓工作区。 |
| `setup` / `init --discover` / `init --wizard` / `repo add/list` / `bootstrap` / `start` | 无需手改 TOML 地完成新人引导、仓库管理与开发线、Agent 选择。 |
| `doctor` / `status` / `status --all` | 验证并显示当前或全部已登记工作区状态。 |
| `next` | 打印当前工作区唯一安全的下一步。活着的 Objective 可能直接给出 `tick` 或 `attention`;`next.commands` 保持为空。 |
| `image doctor` / `image install` | 发现或引导安装可选的 `local-image-gen` sidecar。不代跑出图。 |
| `line create/list` | 创建、登记和查看功能开发线。 |
| `hotfix create` | 从显式生产基线创建 Hotfix 开发线。 |
| `changeset create/list/verify` | 固化并核验一次多仓交付所包含的干净、精确 Git 提交组合。 |
| `objective list/status/explain/tick/attention/plan` | 查看已接受的 Objective 与换工具开场白。写操作在 `objective apply`。 |
| `proof list/show/verify/export/verify-bundle` | 重绑交付 Proof。`verify` 重绑当前工作区;`verify-bundle` 只核便携完整性。`live` 不是 merge。 |
| `config get/set` / `agent list/add/test/discover` / `tool list/install/default/pin` / `open` | 安全管理策略、adapter、工具发现与个人启动偏好,或在正确开发线启动 Agent。 |
| `integration status/install/sync/uninstall` | 管理第一方座位 Skill(`dyro-control-plane`、`dyro-executor`、`dyro-board`、`dyro-dispatch`)。加载座位不是同意改世界。 |
| `task create/open/list/board/status/next/graph/explain/attempts/binding` | 创建或进入任务、管理状态,编译/校验任务图,解释调度,查看 provenance,输出精确复核绑定。 |
| `task run/answer/gates/review/signoff` | 执行任务、回答追问、运行门禁、申请独立复核;需要时记录外部签收。 |
| `task claim --output` / `task evidence build/execution/review` | 一次性领取任务并以“仅创建”文件交给隔离执行器,构建/导入可移植执行证据包,并导入与回执绑定的复核证据。 |
| `task merge` | 将已复核的任务分支合入所属开发线。 |
| `task loop/daemon/stats/decisions` | 受控批处理、调度、台账报表和决策门禁。 |
| `dispatch` | 可选本地多 Agent 派发(L0–L4);仅建议,不替代 gates/merge。 |

实现细节见[零摩擦全局首页 ADR](docs/adr/0003-zero-friction-global-home.md)、[架构与 Profile 契约](docs/architecture.md)、[工作区蓝图契约](docs/workspace-blueprints.md)、[既有控制面迁移指南](docs/migrating-existing-control-planes.md),以及维护者用的 [PyPI 发布说明](docs/publishing.md)。
第一方座位用 `dyro integration` 安装。Proof 用 `dyro proof verify` 重绑,不重跑 gates。

实现细节见[零摩擦全局首页 ADR](docs/adr/0003-zero-friction-global-home.md)、[架构与 Profile 契约](docs/architecture.md)、[工作区蓝图契约](docs/workspace-blueprints.md)、[既有控制面迁移指南](docs/migrating-existing-control-planes.md)、[可选生图 sidecar](docs/image-sidecar.md),以及维护者用的 [PyPI 发布说明](docs/publishing.md)。

## 语言与文档

Expand All @@ -574,3 +583,7 @@ DyroEngineeringFlow 提供完整的本地工作流闭环,以及让高保障团
### 与 Graph Engineering 的关系(可选读)

行业里有时把「多节点 + 路由/并行 + 校验」的工作拓扑称作 **Graph Engineering**(相对单 agent loop)。Dyro 的交付拓扑与之实质相近(TaskGraph、状态机、gates、复核、merge,以及可选的 dispatch 子图),但产品身份仍是 **交付控制面**,不是 agent 编排框架,也不是 Knowledge Graph / GraphRAG。dispatch 仅为建议。详见[架构文档](docs/architecture.md#与-graph-engineering-的关系可选读)。

## 相关兄弟项目

[`local-image-gen`](https://github.com/DandreYang/local-image-gen) 是可选的第一方生图 CLI。同屋不是同一产品:它不是 Dyro 编码工具,也不是托管座位。安装 Dyro 不会顺便装上它。详见[生图 sidecar](docs/image-sidecar.md)。
1 change: 1 addition & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
DyroEngineeringFlow Core(`dyro` CLI)
├─ home: 全局工作区入口、最近目标、任意目录导航(无交付权限)
├─ workspace: anchors、逐仓基线、开发线、Hotfix、存储模式、doctor
├─ image sidecar: 可选的 `local-image-gen` 发现与安装引导(不是座位,也不是编码工具)
├─ launch: Agent adapter 的安全 argv 模板
├─ dispatch: 任务 DAG、决策点、冲突组、状态机、回执、复核与外部签收
├─ verify: gates、日志、台账和统计
Expand Down
69 changes: 69 additions & 0 deletions docs/image-sidecar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Optional image sidecar (`local-image-gen`)

`local-image-gen` is a sibling first-party CLI. It is **not** a Dyro coding tool,
**not** a managed Skill seat, and **not** part of Objective / Change Set / gates
/ merge / push. Dyro only helps a person discover it and read a normalized
health report. Image generation stays on the upstream command.

Official source: <https://github.com/DandreYang/local-image-gen>

## What Dyro does

| Command | What it is allowed to do |
| --- | --- |
| `dyro doctor` | Cheap `PATH` lookup for the `local-image-gen` wrapper. JSON adds `sidecars.local_image_gen.state` = `absent` or `present`. Missing sidecar never fails the workspace. |
| `dyro image doctor` | The only command that may spawn `local-image-gen --doctor`. Reports `absent`, `needs_setup`, `ready`, or `unavailable`. |
| `dyro image install` | Prints the official repository and `install.sh` URL. `--yes` opens the GitHub page. Dyro never runs a remote install script. |
| `local-image-gen …` | Actual generation. Dyro does not wrap billed generate. |

```bash
dyro doctor --format json
dyro image doctor --format json
dyro --dry-run image doctor
dyro --dry-run image install
dyro image install --yes
```

`dyro --dry-run doctor` and `dyro --dry-run image doctor` must not spawn the
sidecar. `dyro --dry-run image install` must not open a browser.

Do **not** install this through `dyro tool install`. Home / `dyro open` stay
coding-tool launchers.

## Workspace output

When a Dyro workspace (`dyro.toml`) is an ancestor and the user omits
`-o` / `--out-dir`, `local-image-gen` writes to `<workspace>/outputs/images/`.
Those files are generated artifacts: they are not Proof, they do not belong in
`repositories/`, and they are not a task worktree. Workspace `doctor()` does
not treat `outputs/images/` as structural damage.

The Codex image path is experimental on the upstream side. Confirm current
status in that repository before relying on it.

## What the navigator seat must not do

`dyro-control-plane` does not run `dyro image`. Isolated Console does not
allowlist `image doctor` or `image install` (`install --yes` opens a browser).
Personal skill directories are never scanned to discover this sidecar. Only the
PATH wrapper named `local-image-gen` counts as installed.

## Normalized `dyro image doctor` JSON

Dyro does not pass through the upstream `--doctor` document. Default output
omits local paths, login files, `api_base`, and secrets. `--include-paths`
may add `output_dir` and `workspace` only.

```json
{
"id": "local-image-gen",
"optional": true,
"state": "absent",
"version": "0.1.0",
"usable_providers": ["grok", "codex"]
}
```

`ready` means the upstream report succeeded and at least one provider has a
subscription or API key. A wrapper on PATH with no backend is `needs_setup`,
not a workspace error.
7 changes: 7 additions & 0 deletions docs/tool-catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,10 @@ project. The user must confirm onboarding separately. The selected workspace
is a default working directory, not an operating-system sandbox; OpenClaw can
still reach other paths allowed to the current user unless its own sandboxing
is configured.

## Out of catalog

`local-image-gen` is an optional sidecar, not a coding tool. Do not add it to
`TOOL_DEFINITIONS` or Skill seats. Discover it with `dyro doctor` / `dyro image
doctor`, and install it from the official repository. See
[image sidecar](image-sidecar.md).
98 changes: 98 additions & 0 deletions src/dyro/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,14 @@
remove_workspace,
set_default_workspace,
)
from .image_sidecar import (
ABSENT_INFO_LINE,
SOURCE_URL,
discover_sidecar,
install_image_sidecar,
probe_sidecar,
require_interactive_install,
)
from .integrations import (
INTEGRATION_CHOICES,
IntegrationState,
Expand Down Expand Up @@ -497,6 +505,7 @@ def _control_plane_command(args: argparse.Namespace) -> str:
"command",
"workspace_command",
"integration_command",
"image_command",
"line_command",
"changeset_command",
"objective_command",
Expand Down Expand Up @@ -526,6 +535,7 @@ def _control_plane_error_code(
return {
"changeset": "CHANGESET_UNAVAILABLE",
"doctor": "WORKSPACE_UNHEALTHY",
"image": "SIDECAR_UNREADABLE",
"integration": "INTEGRATION_UNAVAILABLE",
"line": "LINE_UNAVAILABLE",
"next": "NEXT_STEP_UNAVAILABLE",
Expand Down Expand Up @@ -1547,6 +1557,7 @@ def cmd_doctor(args: argparse.Namespace) -> None:
budget = _control_plane_budget(args) if args.format == "json" else None
findings = doctor(config, read_budget=budget)
failures = [item for item in findings if item.startswith("FAIL")]
sidecar = discover_sidecar()
if args.format == "json":
_print_control_plane_json(
"doctor",
Expand All @@ -1556,6 +1567,7 @@ def cmd_doctor(args: argparse.Namespace) -> None:
_doctor_finding_payload(item, include_paths=args.include_paths)
for item in findings
],
sidecars={"local_image_gen": sidecar.as_dict()},
)
if failures:
raise SystemExit(2)
Expand All @@ -1564,11 +1576,64 @@ def cmd_doctor(args: argparse.Namespace) -> None:
print(muted(f"Profile:{config.name} · 检查仓库、基线与隔离工作区。"))
for finding in findings:
_print_doctor_finding(finding)
if sidecar.state == "absent":
print(ABSENT_INFO_LINE)
if failures:
raise DyroError("doctor 发现结构错误")
print("\n" + success("检查通过。") + " 下一步:" + terminal_value("dyro"))


def cmd_image_doctor(args: argparse.Namespace) -> None:
if args.dry_run:
presence = discover_sidecar()
if args.format == "json":
_print_control_plane_json("image_doctor", **presence.as_dict())
return
print("DRY RUN: 未探测 local-image-gen")
if presence.state == "absent":
print(ABSENT_INFO_LINE)
else:
print("PATH 上已有 local-image-gen;未查询后端。")
return
probe = probe_sidecar()
if args.format == "json":
_print_control_plane_json(
"image_doctor",
**probe.as_dict(include_paths=args.include_paths),
)
if probe.state == "unavailable":
raise SystemExit(2)
return
print("\n" + title("━━ local-image-gen ━━"))
if probe.state == "absent":
print(ABSENT_INFO_LINE)
print("下一步:" + terminal_value("dyro image install"))
return
if probe.state == "ready":
backends = "、".join(probe.usable_providers) or "-"
print(success("状态:ready") + (f" · {probe.version}" if probe.version else ""))
print(f"可用后端:{backends}")
print("下一步:直接运行 " + terminal_value("local-image-gen") + "。Dyro 不代跑出图。")
return
if probe.state == "needs_setup":
print(muted("状态:needs_setup"))
print(probe.message or "已安装 local-image-gen,但没有可用订阅或 API key。")
print(f"来源:{SOURCE_URL}")
print("下一步:按上游文档登录或配置密钥后,再运行 " + terminal_value("dyro image doctor"))
return
print(danger(probe.message or "sidecar 不可读"))
raise SystemExit(2)


def cmd_image_install(args: argparse.Namespace) -> None:
require_interactive_install(
yes=args.yes,
dry_run=args.dry_run,
tty=sys.stdin.isatty() and sys.stdout.isatty(),
)
install_image_sidecar(yes=args.yes, dry_run=args.dry_run)


def cmd_terminology_check(args: argparse.Namespace) -> None:
root = (
_config(args).root
Expand Down Expand Up @@ -4086,6 +4151,39 @@ def build_parser() -> argparse.ArgumentParser:
help="在 JSON 中显式包含本机诊断路径",
)
doctor_parser.set_defaults(func=cmd_doctor)
image = sub.add_parser(
"image",
help="发现并引导安装可选的 local-image-gen sidecar;不代跑计费出图",
)
image_sub = image.add_subparsers(dest="image_command", required=True)
image_doctor = image_sub.add_parser(
"doctor",
help="探测 local-image-gen 是否在 PATH,以及是否有可用后端",
)
image_doctor.add_argument(
"--format", choices=("text", "json"), default="text"
)
image_doctor.add_argument(
"--include-paths",
action="store_true",
help="在 JSON 中显式包含本机产出目录与工作区路径",
)
image_doctor.set_defaults(func=cmd_image_doctor)
image_install = image_sub.add_parser(
"install",
help="展示官方安装来源;不会执行远程安装脚本",
)
image_install.add_argument(
"--yes", action="store_true", help="确认后打开官方仓库页面"
)
image_install.add_argument(
"--dry-run",
dest="dry_run",
action="store_true",
default=argparse.SUPPRESS,
help="仅展示安装来源,不打开浏览器;也兼容全局 --dry-run",
)
image_install.set_defaults(func=cmd_image_install)
terminology = sub.add_parser("terminology", help="使用仓库外策略扫描候选术语")
terminology_sub = terminology.add_subparsers(
dest="terminology_command", required=True
Expand Down
Loading