Merge pull request #603 from fabro-sh/refactor/three-layer-crate-layout
Some checks are pending
Rust / Format (push) Waiting to run
Rust / Clippy (push) Waiting to run
Rust / Test (Linux) (push) Waiting to run
Rust / Test (macOS) (push) Waiting to run
TypeScript / Typecheck (push) Waiting to run
TypeScript / Test (push) Waiting to run
TypeScript / Build (push) Waiting to run
Rust / Generated Docs (push) Waiting to run

refactor: organize crates into apps, components, and foundation
This commit is contained in:
Bryan Helmkamp 2026-07-23 19:27:55 -04:00 committed by GitHub
commit 62c4ccaa93
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
1297 changed files with 471 additions and 461 deletions

View file

@ -17,7 +17,7 @@ Output a report with all the bugs using this format:
<title>title of bug</title>
<description>brief description of bug</description>
<location>
<file>lib/crates/fabro-cli/src/commands/resume.rs</file>
<file>lib/apps/fabro-cli/src/commands/resume.rs</file>
<start_line>115</start_line>
<end_line>115</end_line>
</location>

View file

@ -19,7 +19,7 @@ Output a report with all the bugs using this format:
<severity>important OR nit</severity>
<pre_existing>yes OR no</pre_existing>
<location>
<file>lib/crates/fabro-cli/src/commands/resume.rs</file>
<file>lib/apps/fabro-cli/src/commands/resume.rs</file>
<start_line>115</start_line>
<end_line>115</end_line>
</location>
@ -51,7 +51,7 @@ Here is a real-world example:
<severity>important</severity>
<pre_existing>no</pre_existing>
<location>
<file>lib/crates/fabro-cli/src/commands/resume.rs</file>
<file>lib/apps/fabro-cli/src/commands/resume.rs</file>
<start_line>208</start_line>
<end_line>208</end_line>
</location>

View file

@ -4,32 +4,32 @@ Which source files affect which doc pages. Use this as guidance — also apply j
| Source | Docs |
|--------|------|
| `lib/crates/fabro-cli/src/main.rs`, `lib/crates/fabro-workflow/src/cli/mod.rs`, `lib/crates/fabro-workflow/src/cli/run.rs` | `docs/public/reference/cli.mdx` |
| `lib/crates/fabro-cli/src/cli_config.rs` | `docs/public/reference/cli-configuration.mdx` |
| `lib/crates/fabro-llm/src/cli.rs` | `docs/public/reference/cli.mdx` |
| `lib/crates/fabro-api/src/serve.rs` | `docs/public/reference/cli.mdx` |
| `lib/crates/fabro-workflow/src/parser/*.rs` | `docs/public/reference/dot-language.mdx` |
| `lib/crates/fabro-workflow/src/condition.rs` | `docs/public/reference/dot-language.mdx` |
| `lib/crates/fabro-workflow/src/cli/validate.rs` | `docs/public/reference/dot-language.mdx` |
| `lib/crates/fabro-workflow/src/stylesheet.rs` | `docs/public/workflows/stylesheets.mdx` |
| `lib/crates/fabro-workflow/src/transform.rs` | `docs/public/workflows/variables.mdx` |
| `lib/crates/fabro-workflow/src/handler/*.rs` | `docs/public/workflows/stages-and-nodes.mdx`, `docs/public/reference/dot-language.mdx` |
| `lib/crates/fabro-workflow/src/handler/human.rs` | `docs/public/workflows/human-in-the-loop.mdx` |
| `lib/crates/fabro-workflow/src/cli/run_config.rs` | `docs/public/execution/run-configuration.mdx` |
| `lib/crates/fabro-workflow/src/engine.rs` | `docs/public/core-concepts/how-arc-works.mdx` |
| `lib/crates/fabro-workflow/src/context/*.rs` | `docs/public/execution/context.mdx` |
| `lib/crates/fabro-workflow/src/checkpoint.rs` | `docs/public/execution/checkpoints.mdx` |
| `lib/crates/fabro-workflow/src/retro.rs`, `lib/crates/fabro-workflow/src/retro_agent.rs` | `docs/public/execution/retros.mdx` |
| `lib/crates/fabro-workflow/src/interviewer/*.rs` | `docs/public/execution/interviews.mdx` |
| `lib/crates/fabro-workflow/src/hook/*.rs` | `docs/public/agents/hooks.mdx` |
| `lib/crates/fabro-workflow/src/daytona_sandbox.rs` | `docs/public/integrations/daytona.mdx`, `docs/public/execution/environments.mdx` |
| `lib/crates/fabro-agent/src/tools.rs`, `lib/crates/fabro-agent/src/tool_registry.rs`, `lib/crates/fabro-agent/src/tool_execution.rs` | `docs/public/agents/tools.mdx` |
| `lib/crates/fabro-agent/src/v4a_patch.rs` | `docs/public/agents/tools.mdx` |
| `lib/crates/fabro-agent/src/cli.rs` | `docs/public/agents/permissions.mdx` |
| `lib/crates/fabro-agent/src/subagent.rs` | `docs/public/agents/subagents.mdx` |
| `lib/crates/fabro-agent/src/mcp_integration.rs` | `docs/public/agents/mcp.mdx` |
| `lib/crates/fabro-llm/src/catalog.rs`, `lib/crates/fabro-llm/src/providers/*.rs` | `docs/public/core-concepts/models.mdx` |
| `lib/crates/fabro-slack/src/*.rs` | `docs/public/integrations/slack.mdx` |
| `lib/crates/fabro-mcp/src/*.rs` | `docs/public/agents/mcp.mdx` |
| `lib/crates/fabro-api/src/*.rs` | `docs/public/api-reference/overview.mdx`, `docs/public/api-reference/demo-mode.mdx` |
| `lib/crates/fabro-api/src/server_config.rs` | `docs/public/administration/server-configuration.mdx` |
| `lib/apps/fabro-cli/src/main.rs`, `lib/components/fabro-workflow/src/cli/mod.rs`, `lib/components/fabro-workflow/src/cli/run.rs` | `docs/public/reference/cli.mdx` |
| `lib/apps/fabro-cli/src/cli_config.rs` | `docs/public/reference/cli-configuration.mdx` |
| `lib/components/fabro-llm/src/cli.rs` | `docs/public/reference/cli.mdx` |
| `lib/foundation/fabro-api/src/serve.rs` | `docs/public/reference/cli.mdx` |
| `lib/components/fabro-workflow/src/parser/*.rs` | `docs/public/reference/dot-language.mdx` |
| `lib/components/fabro-workflow/src/condition.rs` | `docs/public/reference/dot-language.mdx` |
| `lib/components/fabro-workflow/src/cli/validate.rs` | `docs/public/reference/dot-language.mdx` |
| `lib/components/fabro-workflow/src/stylesheet.rs` | `docs/public/workflows/stylesheets.mdx` |
| `lib/components/fabro-workflow/src/transform.rs` | `docs/public/workflows/variables.mdx` |
| `lib/components/fabro-workflow/src/handler/*.rs` | `docs/public/workflows/stages-and-nodes.mdx`, `docs/public/reference/dot-language.mdx` |
| `lib/components/fabro-workflow/src/handler/human.rs` | `docs/public/workflows/human-in-the-loop.mdx` |
| `lib/components/fabro-workflow/src/cli/run_config.rs` | `docs/public/execution/run-configuration.mdx` |
| `lib/components/fabro-workflow/src/engine.rs` | `docs/public/core-concepts/how-arc-works.mdx` |
| `lib/components/fabro-workflow/src/context/*.rs` | `docs/public/execution/context.mdx` |
| `lib/components/fabro-workflow/src/checkpoint.rs` | `docs/public/execution/checkpoints.mdx` |
| `lib/components/fabro-workflow/src/retro.rs`, `lib/components/fabro-workflow/src/retro_agent.rs` | `docs/public/execution/retros.mdx` |
| `lib/components/fabro-workflow/src/interviewer/*.rs` | `docs/public/execution/interviews.mdx` |
| `lib/components/fabro-workflow/src/hook/*.rs` | `docs/public/agents/hooks.mdx` |
| `lib/components/fabro-workflow/src/daytona_sandbox.rs` | `docs/public/integrations/daytona.mdx`, `docs/public/execution/environments.mdx` |
| `lib/components/fabro-agent/src/tools.rs`, `lib/components/fabro-agent/src/tool_registry.rs`, `lib/components/fabro-agent/src/tool_execution.rs` | `docs/public/agents/tools.mdx` |
| `lib/components/fabro-agent/src/v4a_patch.rs` | `docs/public/agents/tools.mdx` |
| `lib/components/fabro-agent/src/cli.rs` | `docs/public/agents/permissions.mdx` |
| `lib/components/fabro-agent/src/subagent.rs` | `docs/public/agents/subagents.mdx` |
| `lib/components/fabro-agent/src/mcp_integration.rs` | `docs/public/agents/mcp.mdx` |
| `lib/components/fabro-llm/src/catalog.rs`, `lib/components/fabro-llm/src/providers/*.rs` | `docs/public/core-concepts/models.mdx` |
| `lib/components/fabro-slack/src/*.rs` | `docs/public/integrations/slack.mdx` |
| `lib/components/fabro-mcp/src/*.rs` | `docs/public/agents/mcp.mdx` |
| `lib/foundation/fabro-api/src/*.rs` | `docs/public/api-reference/overview.mdx`, `docs/public/api-reference/demo-mode.mdx` |
| `lib/foundation/fabro-api/src/server_config.rs` | `docs/public/administration/server-configuration.mdx` |

2
.gitattributes vendored
View file

@ -1,2 +1,2 @@
lib/crates/fabro-spa/assets/** linguist-generated=true -diff
lib/apps/fabro-spa/assets/** linguist-generated=true -diff
lib/packages/fabro-api-client/src/** linguist-generated=true

View file

@ -4,7 +4,9 @@ on:
push:
branches: [main]
paths:
- "lib/crates/**"
- "lib/apps/**"
- "lib/components/**"
- "lib/foundation/**"
- "test/**"
- "Cargo.toml"
- "Cargo.lock"
@ -18,7 +20,9 @@ on:
pull_request:
branches: [main]
paths:
- "lib/crates/**"
- "lib/apps/**"
- "lib/components/**"
- "lib/foundation/**"
- "test/**"
- "Cargo.toml"
- "Cargo.lock"
@ -76,7 +80,7 @@ jobs:
- name: Verify legacy auth identity removal
run: |
if git grep -nE 'AuthMode::Disabled|RunAuthMethod|RunSubjectProvenance|\bActorRef\b|\bActorKind\b|AuthenticatedSubject|AuthenticatedService|AuthorizeRunScoped|AuthorizeRunBlob|AuthorizeStageArtifact|AuthorizeCommandLog|auth_method\s*==\s*"disabled"' \
-- lib/crates apps lib/packages docs/public/api-reference/fabro-api.yaml; then
-- lib/apps lib/components lib/foundation apps lib/packages docs/public/api-reference/fabro-api.yaml; then
echo "::error::Legacy auth identities remain in the repository"
exit 1
else

View file

@ -5,7 +5,7 @@ on:
branches: [main]
paths:
- "apps/**"
- "lib/crates/fabro-spa/**"
- "lib/apps/fabro-spa/**"
- "lib/packages/**"
- "package.json"
- "bun.lock"
@ -17,7 +17,7 @@ on:
branches: [main]
paths:
- "apps/**"
- "lib/crates/fabro-spa/**"
- "lib/apps/fabro-spa/**"
- "lib/packages/**"
- "package.json"
- "bun.lock"

4
.gitignore vendored
View file

@ -4,8 +4,8 @@ target
node_modules
apps/fabro-web/dist
apps/fabro-web/.dist-builds/
lib/crates/fabro-spa/assets/*
!lib/crates/fabro-spa/assets/.gitkeep
lib/apps/fabro-spa/assets/*
!lib/apps/fabro-spa/assets/.gitkeep
tmp
evals/swe-bench/repos/
evals/swe-bench/results/

View file

@ -56,7 +56,7 @@ The OpenAPI spec at `docs/public/api-reference/fabro-api.yaml` is the source of
1. Edit `docs/public/api-reference/fabro-api.yaml`
2. `cargo build -p fabro-api` — build.rs regenerates Rust types and client via progenitor
3. Write/update handler in `lib/crates/fabro-server/src/server.rs`, add route to `build_router()`
3. Write/update handler in `lib/apps/fabro-server/src/server.rs`, add route to `build_router()`
4. `cargo nextest run -p fabro-server` — conformance test catches spec/router drift
5. `cd lib/packages/fabro-api-client && bun run generate` — regenerates TypeScript Axios client
@ -64,7 +64,7 @@ The OpenAPI spec at `docs/public/api-reference/fabro-api.yaml` is the source of
- Treat OpenAPI as the source of truth for the wire contract, not as the automatic owner of Rust types.
- Before adding or keeping a generated schema type, search the workspace for an existing hand-written Rust type with the same product meaning.
- If the schema and an existing Rust type have the same semantics and serde shape, reuse the existing type via `lib/crates/fabro-api/build.rs` `with_replacement(...)` instead of generating a parallel API type.
- If the schema and an existing Rust type have the same semantics and serde shape, reuse the existing type via `lib/foundation/fabro-api/build.rs` `with_replacement(...)` instead of generating a parallel API type.
- If two types are close but not identical, prefer proposing changes that align them into one canonical type rather than accepting small drift. It is usually better to iterate the API now than to create permanently split Rust/API types.
- Keep a separate API DTO only when the API is intentionally a projection, summary, or presentation-specific view of internal state. In that case, give it a distinct API-facing name instead of reusing the internal concept name.
- Treat `ApiFoo` aliases and `foo_to_api` / `foo_from_api` adapters as a smell unless they represent a real semantic boundary. They should not exist only to bridge accidental duplicate types.
@ -107,7 +107,7 @@ Before merging changes that add or move shared test helpers, verify:
Fabro is an AI-powered workflow orchestration platform. Workflows are defined as Graphviz graphs, where each node is a stage (agent, prompt, command, conditional, human, parallel, etc.) executed by the workflow engine.
### Rust crates (`lib/crates/`)
### Rust crates (`lib/apps/`, `lib/components/`, and `lib/foundation/`)
- **fabro-cli** — CLI entry point. Commands: `run`, `exec`, `serve`, `validate`, `parse`, `cp`, `model`, `doctor`, `install`, `ps`, `system prune`
- **fabro-workflow** — Core workflow engine. Parses Graphviz graphs, runs stages, manages checkpoints/resume, hooks, and human-in-the-loop interactions
- **fabro-agent** — AI coding agent with tool use (Bash, Read, Write, Edit, Glob, Grep, WebFetch). `Sandbox` trait abstracts execution environments

View file

@ -1,6 +1,12 @@
[workspace]
members = ["lib/crates/*", "test/twin/openai", "test/twin/github"]
default-members = ["lib/crates/fabro-cli"]
members = [
"lib/apps/*",
"lib/components/*",
"lib/foundation/*",
"test/twin/openai",
"test/twin/github",
]
default-members = ["lib/apps/fabro-cli"]
resolver = "2"
[workspace.package]
@ -84,7 +90,7 @@ hmac = "0.12"
sha2 = "0.10"
hex = "0.4"
insta = "1"
fabro-test = { path = "lib/crates/fabro-test" }
fabro-test = { path = "lib/foundation/fabro-test" }
twin-openai = { path = "test/twin/openai" }
twin-github = { path = "test/twin/github" }
tokio-tungstenite = { version = "0.26", features = ["rustls-tls-webpki-roots"] }
@ -100,11 +106,11 @@ rust-embed = "8"
percent-encoding = "2"
minijinja = "=2.19.0"
miette = { version = "7.6", features = ["fancy"] }
fabro-http = { path = "lib/crates/fabro-http" }
fabro-environment = { path = "lib/crates/fabro-environment" }
fabro-options-metadata = { path = "lib/crates/fabro-options-metadata" }
fabro-redact = { path = "lib/crates/fabro-redact" }
fabro-static = { path = "lib/crates/fabro-static" }
fabro-http = { path = "lib/foundation/fabro-http" }
fabro-environment = { path = "lib/components/fabro-environment" }
fabro-options-metadata = { path = "lib/foundation/fabro-options-metadata" }
fabro-redact = { path = "lib/foundation/fabro-redact" }
fabro-static = { path = "lib/foundation/fabro-static" }
graphviz-sys = { git = "https://github.com/fabro-sh/graphviz-sys" }
ref-cast = "1"
strum = { version = "0.28", features = ["derive"] }

View file

@ -23,7 +23,7 @@ export const handle = { wide: true, fullHeight: true };
type Direction = "LR" | "TB";
// Mirrors fabro-graphviz's RANKDIR_RE (lib/crates/fabro-graphviz/src/render.rs) —
// Mirrors fabro-graphviz's RANKDIR_RE (lib/components/fabro-graphviz/src/render.rs) —
// keep the accepted `rankdir=` syntax in sync with that regex.
const RANKDIR_RE = /rankdir\s*=\s*(\w+)/;

View file

@ -2,7 +2,7 @@
## Scope
- Production imports under `lib/crates/fabro-cli/src/**` that still reference `fabro_workflow::*` after the server-owned selector/export refactor.
- Production imports under `lib/apps/fabro-cli/src/**` that still reference `fabro_workflow::*` after the server-owned selector/export refactor.
- Test-only imports are listed separately so the remaining architectural debt is explicit.
## Completed In This Change
@ -16,30 +16,30 @@
| Path | Direct dependency | Why it still exists | Required remediation track |
| --- | --- | --- | --- |
| `lib/crates/fabro-cli/src/commands/pr/create.rs` | `StageOutcome`, `pull_request::maybe_open_pull_request` | CLI still reconstructs store state and runs PR creation logic from the workflow pipeline directly. | Replace with a server API, or extract PR orchestration into a non-engine shared service crate plus API. |
| `lib/crates/fabro-cli/src/commands/run/runner.rs` | `artifact_snapshot::CapturedArtifactInfo`, `artifact_upload::{ArtifactSink, StageArtifactUploader}`, `event::{Emitter, RunEventSink}`, `operations::{self, StartServices}`, `run_control::RunControlState`, `runtime_store::{RunStoreBackend, RunStoreHandle}` | Hidden worker subprocess path still lives inside the CLI crate and embeds the workflow engine directly. | Re-home worker/runtime code outside the user CLI surface, ideally into a dedicated worker crate or binary. |
| `lib/crates/fabro-cli/src/manifest_builder.rs` | `git::{GitSyncStatus, head_sha, sync_status}` | Manifest submission still relies on git helper logic that happens to live in `fabro_workflow`. | Extract git-sync inspection helpers into a non-workflow shared crate/module. |
| `lib/crates/fabro-cli/src/server_client.rs` | `artifact_snapshot::CapturedArtifactInfo` | The upload client reuses a workflow-owned artifact snapshot DTO. | Extract shared artifact snapshot DTOs into `fabro-store`, `fabro-types`, or a dedicated shared crate. |
| `lib/crates/fabro-cli/src/commands/runs/inspect.rs` | `run_status::RunStatus` | CLI output types still depend on engine-owned run status enums. | Extract shared status types into `fabro-types` or switch to API-generated/public store types. |
| `lib/crates/fabro-cli/src/commands/runs/list.rs` | `run_status::RunStatus` | List rendering still depends on engine-owned run status enums. | Extract shared status types into `fabro-types` or switch to API-generated/public store types. |
| `lib/crates/fabro-cli/src/commands/run/attach.rs` | `StageOutcome`, `run_status::RunStatus` | Attach/replay logic still formats engine-owned terminal status types directly. | Extract shared run/conclusion status types into `fabro-types`. |
| `lib/crates/fabro-cli/src/commands/run/output.rs` | `StageOutcome`, `records::Conclusion` | Human-readable completion output still consumes workflow-owned conclusion/status records. | Extract shared conclusion/status DTOs into `fabro-types` or `fabro-store`. |
| `lib/crates/fabro-cli/src/commands/run/wait.rs` | `records::Conclusion`, `run_status::RunStatus` | Wait output still depends on workflow-owned status/conclusion records. | Extract shared conclusion/status DTOs into `fabro-types` or `fabro-store`. |
| `lib/crates/fabro-cli/src/commands/run/run_progress/stage_display.rs` | `StageOutcome`, `format_cost` | Progress UI still depends on shared stage outcome and workflow-owned cost-formatting helper code. | Move formatting helpers into `fabro-util`. |
| `lib/crates/fabro-cli/src/commands/run/run_progress/info_display.rs` | `event::RunNoticeLevel` | Progress UI still formats workflow-owned notice levels directly. | Extract shared notice/event enums into `fabro-types`. |
| `lib/crates/fabro-cli/src/commands/run/run_progress/event.rs` | `event::RunNoticeLevel` | Progress event translation still depends on workflow-owned notice levels. | Extract shared notice/event enums into `fabro-types`. |
| `lib/apps/fabro-cli/src/commands/pr/create.rs` | `StageOutcome`, `pull_request::maybe_open_pull_request` | CLI still reconstructs store state and runs PR creation logic from the workflow pipeline directly. | Replace with a server API, or extract PR orchestration into a non-engine shared service crate plus API. |
| `lib/apps/fabro-cli/src/commands/run/runner.rs` | `artifact_snapshot::CapturedArtifactInfo`, `artifact_upload::{ArtifactSink, StageArtifactUploader}`, `event::{Emitter, RunEventSink}`, `operations::{self, StartServices}`, `run_control::RunControlState`, `runtime_store::{RunStoreBackend, RunStoreHandle}` | Hidden worker subprocess path still lives inside the CLI crate and embeds the workflow engine directly. | Re-home worker/runtime code outside the user CLI surface, ideally into a dedicated worker crate or binary. |
| `lib/apps/fabro-cli/src/manifest_builder.rs` | `git::{GitSyncStatus, head_sha, sync_status}` | Manifest submission still relies on git helper logic that happens to live in `fabro_workflow`. | Extract git-sync inspection helpers into a non-workflow shared crate/module. |
| `lib/apps/fabro-cli/src/server_client.rs` | `artifact_snapshot::CapturedArtifactInfo` | The upload client reuses a workflow-owned artifact snapshot DTO. | Extract shared artifact snapshot DTOs into `fabro-store`, `fabro-types`, or a dedicated shared crate. |
| `lib/apps/fabro-cli/src/commands/runs/inspect.rs` | `run_status::RunStatus` | CLI output types still depend on engine-owned run status enums. | Extract shared status types into `fabro-types` or switch to API-generated/public store types. |
| `lib/apps/fabro-cli/src/commands/runs/list.rs` | `run_status::RunStatus` | List rendering still depends on engine-owned run status enums. | Extract shared status types into `fabro-types` or switch to API-generated/public store types. |
| `lib/apps/fabro-cli/src/commands/run/attach.rs` | `StageOutcome`, `run_status::RunStatus` | Attach/replay logic still formats engine-owned terminal status types directly. | Extract shared run/conclusion status types into `fabro-types`. |
| `lib/apps/fabro-cli/src/commands/run/output.rs` | `StageOutcome`, `records::Conclusion` | Human-readable completion output still consumes workflow-owned conclusion/status records. | Extract shared conclusion/status DTOs into `fabro-types` or `fabro-store`. |
| `lib/apps/fabro-cli/src/commands/run/wait.rs` | `records::Conclusion`, `run_status::RunStatus` | Wait output still depends on workflow-owned status/conclusion records. | Extract shared conclusion/status DTOs into `fabro-types` or `fabro-store`. |
| `lib/apps/fabro-cli/src/commands/run/run_progress/stage_display.rs` | `StageOutcome`, `format_cost` | Progress UI still depends on shared stage outcome and workflow-owned cost-formatting helper code. | Move formatting helpers into `fabro-util`. |
| `lib/apps/fabro-cli/src/commands/run/run_progress/info_display.rs` | `event::RunNoticeLevel` | Progress UI still formats workflow-owned notice levels directly. | Extract shared notice/event enums into `fabro-types`. |
| `lib/apps/fabro-cli/src/commands/run/run_progress/event.rs` | `event::RunNoticeLevel` | Progress event translation still depends on workflow-owned notice levels. | Extract shared notice/event enums into `fabro-types`. |
## Test-Only Couplings
| Path | Direct dependency | Why it still exists | Suggested handling |
| --- | --- | --- | --- |
| `lib/crates/fabro-cli/src/commands/dump.rs` test module | `event::{Event, append_event}` | Unit tests synthesize workflow events directly. | Low priority; keep until a lighter-weight event fixture helper exists. |
| `lib/crates/fabro-cli/src/commands/run/wait.rs` test module | `StageOutcome`, `records::Conclusion`, `run_status::RunStatusRecord` | Output tests construct workflow-owned records directly. | Replace with shared fixture builders once conclusion DTOs move out. |
| `lib/crates/fabro-cli/src/commands/run/run_progress/mod.rs` test module | `event::{Event, RunNoticeLevel, to_run_event, to_run_event_at}`, `outcome::billed_model_usage_from_llm` | Progress tests build engine events directly. | Replace with shared event fixture helpers after event DTO extraction. |
| `lib/crates/fabro-cli/src/commands/run/run_progress/event.rs` test module | `event::{Event, to_run_event}` | Event rendering tests depend on engine event constructors. | Replace with shared event fixture helpers after event DTO extraction. |
| `lib/crates/fabro-cli/src/commands/run/runner.rs` test module | `artifact_upload::StageArtifactUploader` | Worker tests still reach into workflow upload internals. | Keep with worker re-home work; not worth separating first. |
| `lib/crates/fabro-cli/tests/it/workflow/real_cli.rs` | `context::Context`, `event::Emitter`, `handler::agent::{CodergenBackend, CodergenResult}`, `handler::llm::cli::AgentCliBackend` | Integration test exercises the real workflow engine directly through CLI harnesses. | Accept as engine integration coverage or move under workflow-owned test support later. |
| `lib/crates/fabro-cli/tests/it/scenario/recovery.rs` | `operations::{RunTimeline, build_timeline}` | Scenario test inspects rewind timeline internals directly. | Replace after server-owned rewind/timeline APIs exist. |
| `lib/apps/fabro-cli/src/commands/dump.rs` test module | `event::{Event, append_event}` | Unit tests synthesize workflow events directly. | Low priority; keep until a lighter-weight event fixture helper exists. |
| `lib/apps/fabro-cli/src/commands/run/wait.rs` test module | `StageOutcome`, `records::Conclusion`, `run_status::RunStatusRecord` | Output tests construct workflow-owned records directly. | Replace with shared fixture builders once conclusion DTOs move out. |
| `lib/apps/fabro-cli/src/commands/run/run_progress/mod.rs` test module | `event::{Event, RunNoticeLevel, to_run_event, to_run_event_at}`, `outcome::billed_model_usage_from_llm` | Progress tests build engine events directly. | Replace with shared event fixture helpers after event DTO extraction. |
| `lib/apps/fabro-cli/src/commands/run/run_progress/event.rs` test module | `event::{Event, to_run_event}` | Event rendering tests depend on engine event constructors. | Replace with shared event fixture helpers after event DTO extraction. |
| `lib/apps/fabro-cli/src/commands/run/runner.rs` test module | `artifact_upload::StageArtifactUploader` | Worker tests still reach into workflow upload internals. | Keep with worker re-home work; not worth separating first. |
| `lib/apps/fabro-cli/tests/it/workflow/real_cli.rs` | `context::Context`, `event::Emitter`, `handler::agent::{CodergenBackend, CodergenResult}`, `handler::llm::cli::AgentCliBackend` | Integration test exercises the real workflow engine directly through CLI harnesses. | Accept as engine integration coverage or move under workflow-owned test support later. |
| `lib/apps/fabro-cli/tests/it/scenario/recovery.rs` | `operations::{RunTimeline, build_timeline}` | Scenario test inspects rewind timeline internals directly. | Replace after server-owned rewind/timeline APIs exist. |
## Follow-Up Order

View file

@ -48,9 +48,9 @@ That envelope is stronger than most comparator systems. It gives Fabro stable to
Relevant current Fabro sources:
- `docs-internal/events-strategy.md`
- `lib/crates/fabro-workflow/src/event.rs`
- `lib/crates/fabro-types/src/run_event/mod.rs`
- `lib/crates/fabro-agent/src/types.rs`
- `lib/components/fabro-workflow/src/event.rs`
- `lib/foundation/fabro-types/src/run_event/mod.rs`
- `lib/components/fabro-agent/src/types.rs`
## Comparison Matrix

View file

@ -269,21 +269,21 @@ The durable model remains simple: replay ordered events, no duplicate truth laye
An engineer implementing this proposal should make only these structural changes unless a later section explicitly says otherwise.
1. Update [`RunEvent`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-types/src/run_event/mod.rs) to add:
1. Update [`RunEvent`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/foundation/fabro-types/src/run_event/mod.rs) to add:
- `stage_id`
- `parallel_group_id`
- `parallel_branch_id`
- `tool_call_id`
- `actor`
2. Update `RunEvent::to_value()` and `RunEvent` parsing in [`run_event/mod.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-types/src/run_event/mod.rs) so the new envelope fields serialize and deserialize.
3. Extend `StoredEventFields` and `stored_event_fields()` in [`event.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-workflow/src/event.rs) to populate:
2. Update `RunEvent::to_value()` and `RunEvent` parsing in [`run_event/mod.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/foundation/fabro-types/src/run_event/mod.rs) so the new envelope fields serialize and deserialize.
3. Extend `StoredEventFields` and `stored_event_fields()` in [`event.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/components/fabro-workflow/src/event.rs) to populate:
- `stage_id`
- `parallel_group_id`
- `parallel_branch_id`
- `tool_call_id` on tool-lifecycle events
- `actor` when there is a clear primary actor
These values should come from the emitter's current execution context for stage and parallel scope, and from event-specific payloads for `tool_call_id`.
4. Leave [`EventEnvelope`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-store/src/types.rs) structurally unchanged:
4. Leave [`EventEnvelope`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/components/fabro-store/src/types.rs) structurally unchanged:
- `seq: u32`
- `payload: EventPayload`
5. Update API/SSE envelope serialization so wire JSON is flattened:
@ -304,11 +304,11 @@ An engineer implementing this proposal should make only these structural changes
V2 should keep the current hand-coded domain split for prop structs:
- run props in [`run.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-types/src/run_event/run.rs)
- stage and checkpoint props in [`stage.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-types/src/run_event/stage.rs)
- agent props in [`agent.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-types/src/run_event/agent.rs)
- infra/setup props in [`infra.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-types/src/run_event/infra.rs)
- parallel/interview/git/misc props in [`misc.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-types/src/run_event/misc.rs)
- run props in [`run.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/foundation/fabro-types/src/run_event/run.rs)
- stage and checkpoint props in [`stage.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/foundation/fabro-types/src/run_event/stage.rs)
- agent props in [`agent.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/foundation/fabro-types/src/run_event/agent.rs)
- infra/setup props in [`infra.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/foundation/fabro-types/src/run_event/infra.rs)
- parallel/interview/git/misc props in [`misc.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/foundation/fabro-types/src/run_event/misc.rs)
That split is part of the design quality. V2 should keep adding hand-coded prop structs, not collapse everything into generic maps.

View file

@ -1,6 +1,6 @@
# Fabro MCP Server — QA Test Plan
One-time manual QA pass for the 5 tools exposed by `fabro-mcp-server`. Source of truth: `lib/crates/fabro-mcp-server/src/run_tools/`.
One-time manual QA pass for the 5 tools exposed by `fabro-mcp-server`. Source of truth: `lib/apps/fabro-mcp-server/src/run_tools/`.
This plan is **not** a template for adding automated test coverage — it exists to drive a single hands-on sweep against a real running server. Tick boxes as scenarios pass; add notes inline for failures or surprising behavior. Open bugs/PRs for issues found; do not port these scenarios into the Rust test suite.

View file

@ -9,7 +9,7 @@ Migrations are product-facing compatibility code. Treat them like startup and st
Each crate owns the migrations for the data it owns.
```text
lib/crates/<crate>/
lib/<layer>/<crate>/
migrations/
YYYYMMDDSS_descriptive_name.rs
src/migrations.rs

View file

@ -170,14 +170,14 @@ Required payload fields:
Emit from the same places that currently call `put_status`:
- `lib/crates/fabro-workflow/src/operations/create.rs`
- `lib/crates/fabro-workflow/src/operations/start.rs`
- `lib/crates/fabro-workflow/src/operations/resume.rs`
- `lib/crates/fabro-workflow/src/pipeline/finalize.rs`
- `lib/crates/fabro-workflow/src/lifecycle/disk.rs`
- `lib/components/fabro-workflow/src/operations/create.rs`
- `lib/components/fabro-workflow/src/operations/start.rs`
- `lib/components/fabro-workflow/src/operations/resume.rs`
- `lib/components/fabro-workflow/src/pipeline/finalize.rs`
- `lib/components/fabro-workflow/src/lifecycle/disk.rs`
- CLI administrative flows that directly mutate status:
- `lib/crates/fabro-cli/src/commands/runs/rm.rs`
- `lib/crates/fabro-cli/src/commands/run/rewind.rs`
- `lib/apps/fabro-cli/src/commands/runs/rm.rs`
- `lib/apps/fabro-cli/src/commands/run/rewind.rs`
### 2. Enrich `checkpoint.completed` to carry a full checkpoint snapshot
@ -200,11 +200,11 @@ Add fields covering:
Emitter seam:
- `lib/crates/fabro-workflow/src/lifecycle/event.rs`
- `lib/components/fabro-workflow/src/lifecycle/event.rs`
Producer seam for the source checkpoint object:
- `lib/crates/fabro-workflow/src/lifecycle/disk.rs`
- `lib/components/fabro-workflow/src/lifecycle/disk.rs`
Design rule:
@ -231,7 +231,7 @@ Add:
Producer seam:
- `lib/crates/fabro-workflow/src/pipeline/pull_request.rs`
- `lib/components/fabro-workflow/src/pipeline/pull_request.rs`
After this lands, `put_pull_request` should become removable during the later memoized-state cutover.
@ -245,7 +245,7 @@ Do not add a separate storage-shaped event. The final patch is run-level termina
Enrich `run.completed`, using the patch already computed from:
- `lib/crates/fabro-workflow/src/lifecycle/git.rs`
- `lib/components/fabro-workflow/src/lifecycle/git.rs`
Required payload:
@ -287,9 +287,9 @@ Required projected output:
Likely seams:
- `lib/crates/fabro-workflow/src/handler/agent.rs`
- `lib/crates/fabro-workflow/src/handler/llm/api.rs`
- `lib/crates/fabro-workflow/src/pipeline/retro.rs` if retro uses the same forwarded agent session path
- `lib/components/fabro-workflow/src/handler/agent.rs`
- `lib/components/fabro-workflow/src/handler/llm/api.rs`
- `lib/components/fabro-workflow/src/pipeline/retro.rs` if retro uses the same forwarded agent session path
- any CLI-backed LLM path if it still produces `provider_used.json`
Do not keep the current “read JSON sidecar, then `put_node_provider_used`” pattern once this event exists.
@ -304,7 +304,7 @@ Use the existing terminal parallel event rather than adding a storage-shaped eve
Add to `parallel.completed`, emitted from:
- `lib/crates/fabro-workflow/src/handler/parallel.rs`
- `lib/components/fabro-workflow/src/handler/parallel.rs`
Required new payload:
@ -346,19 +346,19 @@ Likely files to touch:
- `docs-internal/events.md`
- `docs-internal/run-directory-keys.md`
- `docs-internal/events-strategy.md`
- `lib/crates/fabro-workflow/src/event.rs`
- `lib/crates/fabro-workflow/src/lifecycle/event.rs`
- `lib/crates/fabro-workflow/src/lifecycle/disk.rs`
- `lib/crates/fabro-workflow/src/lifecycle/git.rs`
- `lib/crates/fabro-workflow/src/operations/create.rs`
- `lib/crates/fabro-workflow/src/operations/start.rs`
- `lib/crates/fabro-workflow/src/operations/resume.rs`
- `lib/crates/fabro-workflow/src/pipeline/finalize.rs`
- `lib/crates/fabro-workflow/src/pipeline/pull_request.rs`
- `lib/crates/fabro-workflow/src/handler/agent.rs`
- `lib/crates/fabro-workflow/src/handler/parallel.rs`
- `lib/crates/fabro-cli/src/commands/runs/rm.rs`
- `lib/crates/fabro-cli/src/commands/run/rewind.rs`
- `lib/components/fabro-workflow/src/event.rs`
- `lib/components/fabro-workflow/src/lifecycle/event.rs`
- `lib/components/fabro-workflow/src/lifecycle/disk.rs`
- `lib/components/fabro-workflow/src/lifecycle/git.rs`
- `lib/components/fabro-workflow/src/operations/create.rs`
- `lib/components/fabro-workflow/src/operations/start.rs`
- `lib/components/fabro-workflow/src/operations/resume.rs`
- `lib/components/fabro-workflow/src/pipeline/finalize.rs`
- `lib/components/fabro-workflow/src/pipeline/pull_request.rs`
- `lib/components/fabro-workflow/src/handler/agent.rs`
- `lib/components/fabro-workflow/src/handler/parallel.rs`
- `lib/apps/fabro-cli/src/commands/runs/rm.rs`
- `lib/apps/fabro-cli/src/commands/run/rewind.rs`
- tests in `fabro-workflow`, `fabro-cli`, and `fabro-store`
## Phases

View file

@ -5,8 +5,8 @@ This document maps the files that still live under a run scratch directory. Dura
Scope:
- Scratch root: `~/.fabro/scratch/YYYYMMDD-{run_id}/`
- This covers local run files only
- Persistent store keys live in `lib/crates/fabro-store/src/keys.rs`
- Artifact object-store keys live in `lib/crates/fabro-store/src/artifact_store.rs`
- Persistent store keys live in `lib/components/fabro-store/src/keys.rs`
- Artifact object-store keys live in `lib/components/fabro-store/src/artifact_store.rs`
There is no `_init.json` anymore. Run existence in the database is determined by stored run events, and local scratch directories are managed separately under `scratch/`.

View file

@ -22,7 +22,7 @@ Method:
### [x] 1. Change two slow `exec` mock responses from retriable `500` to non-retriable `400`
Files:
- `lib/crates/fabro-cli/tests/it/cmd/exec.rs`
- `lib/apps/fabro-cli/tests/it/cmd/exec.rs`
Measured evidence:
- `fabro-cli::it::cmd::exec::exec_cli_server_target_overrides_configured_server_target`: `6.858s` median
@ -32,7 +32,7 @@ Measured evidence:
- mocked `400`: `0.053s` median
Implementation status:
- Implemented in `lib/crates/fabro-cli/tests/it/cmd/exec.rs`
- Implemented in `lib/apps/fabro-cli/tests/it/cmd/exec.rs`
- Verified with `ulimit -n 4096` via 5 targeted nextest runs per test
- Post-change nextest exec-time medians:
- `exec_server_target_uses_remote_transport_instead_of_local_api_key_resolution`: `1.580s`
@ -57,7 +57,7 @@ Cons:
### 2. Short-circuit delete-path worker grace for already-terminal runs
Files:
- `lib/crates/fabro-server/src/server.rs`
- `lib/apps/fabro-server/src/server.rs`
Measured evidence:
- `fabro-cli::it::cmd::system_prune::system_prune_yes_deletes_matching_runs`: `10.477s`
@ -87,11 +87,11 @@ Cons:
### [x] 3. Collapse the five abnormally slow `help` integration tests into one smoke test or a lighter harness
Files:
- `lib/crates/fabro-cli/tests/it/cmd/artifact.rs`
- `lib/crates/fabro-cli/tests/it/cmd/artifact_list.rs`
- `lib/crates/fabro-cli/tests/it/cmd/artifact_cp.rs`
- `lib/crates/fabro-cli/tests/it/cmd/config.rs`
- `lib/crates/fabro-cli/tests/it/cmd/attach.rs`
- `lib/apps/fabro-cli/tests/it/cmd/artifact.rs`
- `lib/apps/fabro-cli/tests/it/cmd/artifact_list.rs`
- `lib/apps/fabro-cli/tests/it/cmd/artifact_cp.rs`
- `lib/apps/fabro-cli/tests/it/cmd/config.rs`
- `lib/apps/fabro-cli/tests/it/cmd/attach.rs`
Measured evidence:
- Slow `help` tests:
@ -131,8 +131,8 @@ Cons:
### [x] 4. Replace `doctor_no_color_when_no_color_set` with a render-path assertion
Files:
- `lib/crates/fabro-cli/tests/it/cmd/doctor.rs`
- `lib/crates/fabro-util/src/check_report.rs`
- `lib/apps/fabro-cli/tests/it/cmd/doctor.rs`
- `lib/foundation/fabro-util/src/check_report.rs`
Measured evidence:
- `fabro-cli::it::cmd::doctor::doctor_no_color_when_no_color_set`: `5.131s`
@ -144,7 +144,7 @@ Estimated impact:
Implementation status:
- Implemented by deleting `fabro-cli::it::cmd::doctor::doctor_no_color_when_no_color_set`
- Added a unit-level render assertion in `lib/crates/fabro-cli/src/commands/doctor.rs`:
- Added a unit-level render assertion in `lib/apps/fabro-cli/src/commands/doctor.rs`:
- `render_report_text_without_color_has_no_ansi`
- Verified with `ulimit -n 4096; cargo nextest run -p fabro-cli render_report_text_without_color_has_no_ansi --status-level fail --final-status-level fail --show-progress none`
- Verification result: `1 passed`
@ -166,8 +166,8 @@ Cons:
### [x] 5. Fix local Unix-socket autostart so it doesn't burn the full 5s readiness wait
Files:
- `lib/crates/fabro-cli/src/server_client.rs`
- `lib/crates/fabro-cli/tests/it/cmd/server_start.rs`
- `lib/apps/fabro-cli/src/server_client.rs`
- `lib/apps/fabro-cli/tests/it/cmd/server_start.rs`
Measured evidence:
- Pre-fix 5-run timing for `fabro-cli::it::cmd::server_start::concurrent_autostart_converges_on_one_shared_daemon_and_cleans_up`:
@ -197,7 +197,7 @@ Implementation status:
- Implemented by splitting the Unix-socket connection path into:
- a single immediate health probe before autostart
- the existing retrying readiness wait after autostart
- Kept the original integration test coverage in `lib/crates/fabro-cli/tests/it/cmd/server_start.rs`
- Kept the original integration test coverage in `lib/apps/fabro-cli/tests/it/cmd/server_start.rs`
- Verified with `ulimit -n 4096; cargo nextest run -p fabro-cli concurrent_autostart_converges_on_one_shared_daemon_and_cleans_up --status-level fail --final-status-level fail --show-progress none`
- Verification result: `1 passed`
- Post-change 5-run timing for `fabro-cli::it::cmd::server_start::concurrent_autostart_converges_on_one_shared_daemon_and_cleans_up`:
@ -217,7 +217,7 @@ Implementation status:
### [x] 6. Collapse three lightweight `attach` smoke tests into one scenario-style test
Files:
- `lib/crates/fabro-cli/tests/it/cmd/attach.rs`
- `lib/apps/fabro-cli/tests/it/cmd/attach.rs`
Measured evidence:
- `attach_requires_run_arg`: `1.595s`
@ -230,7 +230,7 @@ Estimated impact:
- Conservative recoverable time: about `3.15s`
Implementation status:
- Implemented by removing the 3 command-owned smoke tests from `lib/crates/fabro-cli/tests/it/cmd/attach.rs`
- Implemented by removing the 3 command-owned smoke tests from `lib/apps/fabro-cli/tests/it/cmd/attach.rs`
- Added `fabro-cli::it::scenario::smoke::attach_smoke_covers_arg_validation_and_remote_server_behaviors`
- Verified with `ulimit -n 4096; cargo nextest run -p fabro-cli attach_smoke_covers_arg_validation_and_remote_server_behaviors --status-level fail --final-status-level fail --show-progress none`
- Verification result: `1 passed`
@ -256,7 +256,7 @@ Cons:
### [x] 7. Collapse the three `completion` tests
Files:
- `lib/crates/fabro-cli/tests/it/cmd/completion.rs`
- `lib/apps/fabro-cli/tests/it/cmd/completion.rs`
Measured evidence:
- `completion::generates_zsh_completions`: `1.567s`
@ -295,7 +295,7 @@ Cons:
### [x] 8. Remove or merge the duplicate attach replay test
Files:
- `lib/crates/fabro-cli/tests/it/cmd/attach.rs`
- `lib/apps/fabro-cli/tests/it/cmd/attach.rs`
Measured evidence:
- `attach_replays_completed_detached_run`: `2.696s`
@ -303,7 +303,7 @@ Measured evidence:
- The two tests are currently identical in code and assertions
Implementation status:
- Implemented by removing the duplicate test from `lib/crates/fabro-cli/tests/it/cmd/attach.rs`
- Implemented by removing the duplicate test from `lib/apps/fabro-cli/tests/it/cmd/attach.rs`
- Verified with `ulimit -n 4096; cargo nextest run -p fabro-cli attach_replays_completed_detached_run --status-level fail --final-status-level fail --show-progress none`
- Verification result: `1 passed`
@ -325,7 +325,7 @@ Cons:
### [x] 9. Make `attach_before_completion_streams_to_finished_state` event-driven instead of sleep-driven
Files:
- `lib/crates/fabro-cli/tests/it/cmd/attach.rs`
- `lib/apps/fabro-cli/tests/it/cmd/attach.rs`
Measured evidence:
- `attach_before_completion_streams_to_finished_state`: `3.043s`
@ -333,7 +333,7 @@ Measured evidence:
- `write_gated_workflow()` adds another fixed `sleep 0.2`
Implementation status:
- Implemented by replacing the fixed 1-second gate-release sleep with a real attach-output signal in `lib/crates/fabro-cli/tests/it/cmd/attach.rs`
- Implemented by replacing the fixed 1-second gate-release sleep with a real attach-output signal in `lib/apps/fabro-cli/tests/it/cmd/attach.rs`
- The test now spawns `fabro attach`, waits for replayed stderr output (`✓ start`), then releases the workflow gate
- Verified with `ulimit -n 4096; cargo nextest run -p fabro-cli attach_before_completion_streams_to_finished_state --status-level fail --final-status-level fail --show-progress none`
- Verification result: `1 passed`
@ -361,14 +361,14 @@ Cons:
### [x] 10. Remove or parameterize the fixed `sleep 0.2` in `write_gated_workflow()`
Files:
- `lib/crates/fabro-cli/tests/it/cmd/support.rs`
- `lib/apps/fabro-cli/tests/it/cmd/support.rs`
Measured evidence:
- `write_gated_workflow()` hardcodes `sleep 0.2`
- The helper is used in 6 cmd tests
Implementation status:
- Implemented by deleting the fixed `sleep 0.2` from `write_gated_workflow()` in `lib/crates/fabro-cli/tests/it/cmd/support.rs`
- Implemented by deleting the fixed `sleep 0.2` from `write_gated_workflow()` in `lib/apps/fabro-cli/tests/it/cmd/support.rs`
- Verified with `ulimit -n 4096; cargo nextest run -p fabro-cli -E 'test(attach_before_completion_streams_to_finished_state) | test(ctrl_c_cancels_active_run_via_server) | test(rm_force_terminates_active_run_worker) | test(start_rejects_already_active_or_completed_run) | test(start_runs_under_server_ownership_without_launcher_record)' --status-level fail --final-status-level fail --show-progress none`
- Verification result: `5 passed`
- Targeted 5-pass benchmark with `ulimit -n 4096` over the 5 tests that currently use the helper:

View file

@ -37,7 +37,7 @@ This is the right place for:
If the setup requires direct writes to internal run files or runtime directories, prefer this layer over `fabro-cli/tests/it`.
### `lib/crates/fabro-cli/tests/it/cmd/*.rs`
### `lib/apps/fabro-cli/tests/it/cmd/*.rs`
`cmd/*` tests are command-owned tests.
@ -64,7 +64,7 @@ Bad command-test assertions:
- behavior primarily owned by another command
- runtime internals that only exist because the test planted them by hand
### `lib/crates/fabro-cli/tests/it/workflow/*.rs`
### `lib/apps/fabro-cli/tests/it/workflow/*.rs`
`workflow/*` tests are black-box workflow-behavior tests.
@ -79,7 +79,7 @@ Examples:
These tests should focus on the workflow's observed behavior, not on CLI help text or command argument validation.
### `lib/crates/fabro-cli/tests/it/scenario/*.rs`
### `lib/apps/fabro-cli/tests/it/scenario/*.rs`
`scenario/*` tests are cross-command lifecycle tests.

View file

@ -43,7 +43,7 @@ The `fabro-api` crate generates Rust structs, enums, and a `reqwest`-based HTTP
A `build.rs` script reads `docs/public/api-reference/fabro-api.yaml`, patches it from OpenAPI 3.1 to 3.0 for progenitor compatibility, and generates both types and a client. The generated code is written to `OUT_DIR` and included via:
```rust
// lib/crates/fabro-api/src/lib.rs
// lib/foundation/fabro-api/src/lib.rs
include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
```

View file

@ -73,7 +73,7 @@ Use Claude Code's plan mode to collaborate on an implementation plan. Go back an
> /plan Add retry logic to the webhook delivery system
Planning...
1. Add RetryPolicy struct to lib/crates/fabro-webhooks/src/policy.rs
1. Add RetryPolicy struct to lib/components/fabro-webhooks/src/policy.rs
2. Implement exponential backoff with jitter
3. Add max_retries field to WebhookConfig
4. Write tests for retry timing, max attempts, and jitter bounds

View file

@ -18,40 +18,40 @@ sleep_inhibitor = ["dep:core-foundation"]
workspace = true
[dependencies]
fabro-auth = { path = "../fabro-auth" }
fabro-config = { path = "../fabro-config" }
fabro-environment = { path = "../fabro-environment" }
fabro-llm = { path = "../fabro-llm" }
fabro-model = { path = "../fabro-model" }
fabro-oauth = { path = "../fabro-oauth" }
fabro-github = { path = "../fabro-github" }
fabro-agent = { path = "../fabro-agent" }
fabro-dump = { path = "../fabro-dump" }
fabro-hooks = { path = "../fabro-hooks" }
fabro-install = { path = "../fabro-install" }
fabro-interview = { path = "../fabro-interview" }
fabro-mcp = { path = "../fabro-mcp" }
fabro-auth = { path = "../../foundation/fabro-auth" }
fabro-config = { path = "../../foundation/fabro-config" }
fabro-environment = { path = "../../components/fabro-environment" }
fabro-llm = { path = "../../components/fabro-llm" }
fabro-model = { path = "../../foundation/fabro-model" }
fabro-oauth = { path = "../../foundation/fabro-oauth" }
fabro-github = { path = "../../components/fabro-github" }
fabro-agent = { path = "../../components/fabro-agent" }
fabro-dump = { path = "../../components/fabro-dump" }
fabro-hooks = { path = "../../components/fabro-hooks" }
fabro-install = { path = "../../components/fabro-install" }
fabro-interview = { path = "../../components/fabro-interview" }
fabro-mcp = { path = "../../components/fabro-mcp" }
fabro-mcp-server = { path = "../fabro-mcp-server" }
fabro-manifest = { path = "../fabro-manifest" }
fabro-proc = { path = "../fabro-proc" }
fabro-sandbox = { path = "../fabro-sandbox", features = ["daytona"] }
fabro-checkpoint = { path = "../fabro-checkpoint" }
fabro-graphviz = { path = "../fabro-graphviz" }
fabro-validate = { path = "../fabro-validate" }
fabro-workflow = { path = "../fabro-workflow" }
fabro-manifest = { path = "../../components/fabro-manifest" }
fabro-proc = { path = "../../foundation/fabro-proc" }
fabro-sandbox = { path = "../../components/fabro-sandbox", features = ["daytona"] }
fabro-checkpoint = { path = "../../components/fabro-checkpoint" }
fabro-graphviz = { path = "../../components/fabro-graphviz" }
fabro-validate = { path = "../../components/fabro-validate" }
fabro-workflow = { path = "../../components/fabro-workflow" }
fabro-server = { path = "../fabro-server" }
fabro-client = { path = "../fabro-client" }
fabro-api = { path = "../fabro-api" }
fabro-telemetry = { path = "../fabro-telemetry" }
fabro-store = { path = "../fabro-store" }
fabro-vault = { path = "../fabro-vault" }
fabro-types = { path = "../fabro-types", features = ["clap"] }
fabro-client = { path = "../../foundation/fabro-client" }
fabro-api = { path = "../../foundation/fabro-api" }
fabro-telemetry = { path = "../../foundation/fabro-telemetry" }
fabro-store = { path = "../../components/fabro-store" }
fabro-vault = { path = "../../foundation/fabro-vault" }
fabro-types = { path = "../../foundation/fabro-types", features = ["clap"] }
fabro-redact.workspace = true
fabro-util = { path = "../fabro-util" }
fabro-util = { path = "../../foundation/fabro-util" }
fabro-http.workspace = true
fabro-static.workspace = true
fabro-template = { path = "../fabro-template" }
fabro-tool = { path = "../fabro-tool" }
fabro-template = { path = "../../foundation/fabro-template" }
fabro-tool = { path = "../../components/fabro-tool" }
clap.workspace = true
clap_complete.workspace = true
cli-table.workspace = true
@ -111,16 +111,16 @@ core-foundation = { version = "0.9", optional = true }
openssl = { version = "0.10", features = ["vendored"] }
[build-dependencies]
fabro-build-support = { path = "../build-support" }
fabro-build-support = { path = "../../foundation/build-support" }
chrono = { workspace = true }
[dev-dependencies]
assert_cmd = "2"
fabro-acp = { path = "../fabro-acp", features = ["test-support"] }
fabro-build-support = { path = "../build-support" }
fabro-acp = { path = "../../components/fabro-acp", features = ["test-support"] }
fabro-build-support = { path = "../../foundation/build-support" }
fabro-server = { path = "../fabro-server", features = ["test-support"] }
fabro-workflow = { path = "../fabro-workflow", features = ["test-support"] }
fabro-types = { path = "../fabro-types", features = ["clap", "test-support"] }
fabro-workflow = { path = "../../components/fabro-workflow", features = ["test-support"] }
fabro-types = { path = "../../foundation/fabro-types", features = ["clap", "test-support"] }
insta = { workspace = true, features = ["filters"] }
paste = "1"
predicates = "3"
@ -129,7 +129,7 @@ tempfile = "3"
temp-env = "0.3"
httpmock = "0.8"
fabro-test = { workspace = true }
fabro-macros = { path = "../fabro-macros" }
fabro-macros = { path = "../../foundation/fabro-macros" }
hkdf.workspace = true
reqwest = { workspace = true, features = ["cookies"] }
tokio = { workspace = true, features = ["test-util", "macros"] }

Some files were not shown because too many files have changed in this diff Show more