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
8 changes: 6 additions & 2 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ When
- Materialized `sources/tenant`, `sources/devkit`, and optional
`sources/shared-addons`.
- Generated runtime output under `.generated/`.
- Disposable local state under `state/`.
- Legacy or disposable local runtime output under `state/`, when an older
workspace still has it.
- Optional local `AGENTS.override.md` for non-secret implementation facts that
should stay out of generated docs. Secrets still belong in `.env`.

### Control plane

Expand All @@ -81,11 +84,12 @@ When
README.md
workspace.lock.toml
.generated/
AGENTS.override.md # optional local, untracked, non-secret operator notes
sources/
tenant/
devkit/
shared-addons/
state/
state/ # legacy or disposable local runtime output when present
```

## Design Goal
Expand Down
2 changes: 2 additions & 0 deletions docs/tooling/command-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,7 @@ uv run platform workspace scaffold-tenant-overlay \

- Do not hand-edit generated workspace-root cockpit files.
- If the workspace surface is wrong, fix `odoo-devkit` and re-sync.
- Keep implementation-specific, non-secret local facts in an untracked
`AGENTS.override.md`; keep credentials in `.env`.
- Keep tenant repo docs thin; use the generated workspace docs index for shared
guidance.
4 changes: 4 additions & 0 deletions docs/tooling/workspace-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ Purpose
of hand-maintaining root markdown files.
- Generate `AGENTS.md`, `docs/README.md`, and `docs/session-prompt.md` from
that config.
- Point operators to an optional local `AGENTS.override.md` for non-secret
implementation facts that must not be baked into generated shared docs.
- Keep non-repo workspace roots thin, link-heavy, and synced from
`odoo-devkit` instead of hand-maintaining the same entrypoint docs.

Expand All @@ -107,6 +109,8 @@ Purpose
tenant `workspace sync` surface.
- Re-render both repo listings and section-level guidance bullets from the
tracked cockpit config.
- Preserve local-only notes by linking to `AGENTS.override.md` instead of
copying implementation details into generated markdown.

## `workspace status-cockpit-root`

Expand Down
19 changes: 10 additions & 9 deletions odoo_devkit/workspace_cockpit.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ def _render_workspace_agents(manifest: WorkspaceCockpitManifest) -> str:
primary_repos = _repos_for_group(manifest, "primary")
upstream_repos = _repos_for_group(manifest, "upstream_image")
devkit_repo = _repo_for_role(manifest, "devkit")
sync_command = f"uv --directory {devkit_repo.path} run platform workspace sync-cockpit-root --config workspace-cockpit.toml"
sync_command = f"uv --project {devkit_repo.path} run platform workspace sync-cockpit-root --config workspace-cockpit.toml"
repo_map_lines = "\n".join(_format_repo_map_line(repo) for repo in primary_repos)
upstream_lines = "\n".join(_format_repo_map_line(repo) for repo in upstream_repos)
first_read_lines = _render_markdown_bullets(manifest.agents_first_read_lines)
Expand Down Expand Up @@ -225,7 +225,7 @@ def _render_workspace_docs_index(manifest: WorkspaceCockpitManifest) -> str:
upstream_lines = "\n".join(
f"- {repo.label}: [{_docs_link_target(repo.path)}]({_docs_link_target(repo.path)})" for repo in upstream_repos
)
sync_command = f"uv --directory {devkit_repo.path} run platform workspace sync-cockpit-root --config workspace-cockpit.toml"
sync_command = f"uv --project {devkit_repo.path} run platform workspace sync-cockpit-root --config workspace-cockpit.toml"
external_reference_lines = _render_markdown_bullets(manifest.docs_external_reference_lines)
working_split_lines = _render_markdown_bullets(manifest.docs_working_split_lines)
operational_note_lines = _render_markdown_bullets(manifest.docs_operational_note_lines)
Expand Down Expand Up @@ -311,7 +311,7 @@ def _format_repo_map_line(repo: WorkspaceCockpitRepoDefinition) -> str:


def _status_command(devkit_repo: WorkspaceCockpitRepoDefinition) -> str:
return f"uv --directory {devkit_repo.path} run platform workspace status-cockpit-root --config workspace-cockpit.toml"
return f"uv --project {devkit_repo.path} run platform workspace status-cockpit-root --config workspace-cockpit.toml"


def _render_markdown_bullets(lines: tuple[str, ...]) -> str:
Expand All @@ -325,6 +325,7 @@ def _render_plain_bullets(lines: tuple[str, ...]) -> str:
def _default_agents_first_read_lines() -> tuple[str, ...]:
return (
"Open [docs/README.md](docs/README.md) in this workspace root first.",
"If present, open [AGENTS.override.md](AGENTS.override.md) for local, non-secret operator details before touching infra, SSH, tunnels, or remote service configuration.",
"Use [sources/devkit/AGENTS.md](sources/devkit/AGENTS.md) for the canonical shared operating guide.",
"Use [sources/devkit/docs/README.md](sources/devkit/docs/README.md) for the canonical shared docs index.",
"Use the tenant-specific `workspace.toml` manifests when you need to run current local runtime commands through `odoo-devkit`.",
Expand All @@ -334,9 +335,9 @@ def _default_agents_first_read_lines() -> tuple[str, ...]:
def _default_agents_ownership_lines() -> tuple[str, ...]:
return (
"`odoo-devkit` owns shared DX/runtime/workspace behavior plus local runtime and explicit data workflows.",
"`harbor` owns remote release actions, deployment truth, release tuples, and promotion evidence.",
"`launchplane` owns remote release actions, deployment truth, release tuples, and promotion evidence.",
"Stable remote lanes are `testing` and `prod`.",
"Harbor PR previews replace any durable shared `dev` lane.",
"Launchplane PR previews replace any durable shared `dev` lane.",
)


Expand All @@ -359,9 +360,9 @@ def _default_docs_external_reference_lines() -> tuple[str, ...]:
def _default_docs_working_split_lines() -> tuple[str, ...]:
return (
"Use `odoo-devkit` for shared DX/runtime/workspace behavior and for local runtime plus explicit data workflows.",
"Use `harbor` for remote release actions, deployment truth, release tuples, and promotion evidence.",
"Use `launchplane` for remote release actions, deployment truth, release tuples, and promotion evidence.",
"Stable remote lanes are `testing` and `prod`.",
"Harbor PR previews replace any durable shared `dev` lane.",
"Launchplane PR previews replace any durable shared `dev` lane.",
)


Expand All @@ -375,9 +376,9 @@ def _default_session_prompt_rule_lines() -> tuple[str, ...]:
return (
"Treat repos under sources/ as the primary system under construction.",
"Use odoo-devkit for shared DX/runtime/workspace behavior and local/data workflows.",
"Use harbor for remote release actions, deployment truth, release tuples, and promotion evidence.",
"Use launchplane for remote release actions, deployment truth, release tuples, and promotion evidence.",
"Stable remote lanes are testing and prod.",
"Harbor PR previews replace any durable shared dev lane.",
"Launchplane PR previews replace any durable shared dev lane.",
"Do not bring odoo-ai into the normal workspace context unless the task is explicit archaeology.",
"Keep tenant repos thin and tenant-specific; fix shared behavior in devkit.",
"When `workspace-cockpit.toml`, the workspace root, and source repos disagree, treat the source repos as the source of truth, then regenerate the cockpit.",
Expand Down
15 changes: 8 additions & 7 deletions odoo_devkit/workspace_surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,19 @@ def _render_workspace_agents(
"This file is generated by `uv run platform workspace sync`. Treat the workspace root as the shared Every Code cockpit for this tenant while keeping hand-edited source-of-truth changes in the underlying repos.\n\n"
"## Start Here\n\n"
"- Open `docs/README.md` in this workspace root first. It routes to the shared devkit docs and the tenant-specific docs.\n"
"- If present, open `AGENTS.override.md` for local, non-secret operator details before touching infra, SSH, tunnels, or remote service configuration. Keep secrets in `.env`.\n"
"- For the deeper shared operating guide, open `sources/devkit/AGENTS.md`.\n"
"- For workspace command details, open `sources/devkit/docs/tooling/workspace-cli.md`.\n"
"- Use `sources/tenant/` for the active tenant source tree. PyCharm should still open that tenant repo directly by default.\n"
"- Use `sources/devkit/` for shared DX/runtime/tooling ownership. That repo is the canonical owner of the shared operating guide and docs used to generate this workspace surface.\n"
"- Treat `platform runtime` as the home for local runtime work plus explicit Dokploy-managed data workflows. Stable remote lanes are `testing` and `prod`; Harbor PR previews replace a durable `dev` lane; release actions such as ship/promote/gate stay in `harbor`.\n"
"- Treat `platform runtime` as the home for local runtime work plus explicit Dokploy-managed data workflows. Stable remote lanes are `testing` and `prod`; Launchplane PR previews replace a durable `dev` lane; release actions such as ship/promote/gate stay in `launchplane`.\n"
f"{shared_addons_pointer}\n"
"- Treat `.generated/` and `state/` as managed output only. They are safe to regenerate and should not become a long-term home for hand-edited code or secrets.\n\n"
"- Treat `.generated/` as managed output only. Treat `state/`, when present, as legacy or disposable local runtime output; it should not become a long-term home for hand-edited code or secrets.\n\n"
"## Source Of Truth Rules\n\n"
f"- Tenant handwritten code lives in `sources/tenant/` and resolves to `{tenant_repo_path}`.\n"
f"- Shared DX/docs/runtime guidance lives in `sources/devkit/` and resolves to `{devkit_repo_path}`.\n"
f"{shared_addons_source_of_truth}\n"
"- Generated runtime files live under `.generated/`. Disposable logs, caches, and state live under `state/`.\n"
"- Generated runtime files live under `.generated/`. Legacy or disposable local runtime output may live under `state/` when an older workspace still has it.\n"
f"- The tracked manifest that defines this workspace is `{manifest.manifest_path}`.\n\n"
"## Workspace Commands\n\n"
f"- Resync this workspace with `{tenant_workspace_sync_command}`.\n"
Expand All @@ -131,7 +132,7 @@ def _render_workspace_agents(
"- Shared devkit checkout: `sources/devkit/`\n"
"- Shared addons checkout: `sources/shared-addons/` when declared\n"
"- Generated runtime output: `.generated/`\n"
"- Disposable local state: `state/`\n"
"- Legacy or disposable local runtime output: `state/` when present\n"
)


Expand Down Expand Up @@ -239,7 +240,7 @@ def _render_workspace_docs_index(
"- PyCharm should keep opening the tenant repo directly so search/indexing stays focused on the client code.\n"
f"- Preferred tenant-root sync command: `{tenant_workspace_sync_command}`.\n"
f"- Preferred tenant-root status command: `{tenant_workspace_status_command}`.\n"
"- Treat `platform runtime` as the local-runtime and remote-data-workflow surface. Stable remote lanes are `testing` and `prod`; Harbor PR previews replace a durable `dev` lane; release actions for remote environments belong in `harbor`.\n"
"- Treat `platform runtime` as the local-runtime and remote-data-workflow surface. Stable remote lanes are `testing` and `prod`; Launchplane PR previews replace a durable `dev` lane; release actions for remote environments belong in `launchplane`.\n"
"- When in doubt about ownership, fix the source repo under `sources/` instead of editing generated files in the workspace root.\n"
)

Expand Down Expand Up @@ -276,9 +277,9 @@ def _render_workspace_session_prompt(
"- Keep tenant code in sources/tenant.\n"
"- Keep shared DX/runtime/workspace behavior in odoo-devkit.\n"
"- Use platform runtime for local runtime and explicit data workflows.\n"
"- Use harbor for remote release actions.\n"
"- Use launchplane for remote release actions.\n"
"- Stable remote lanes are testing and prod.\n"
"- Harbor PR previews replace any durable shared dev lane.\n"
"- Launchplane PR previews replace any durable shared dev lane.\n"
"- When generated files disagree with source repos, fix the source repo or generator rather than hand-editing generated output.\n"
"```\n"
)
Expand Down
2 changes: 1 addition & 1 deletion templates/tenant-overlay/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Treat this file as the thin tenant-specific overlay for a tenant repo.
`odoo-devkit` repo while shared-addon source stays explicit in the manifest.
- Convenience shell commands under `scripts/` for workspace sync/status from
the tenant repo root.
- Remote release actions belong in `harbor`; keep this overlay
- Remote release actions belong in `launchplane`; keep this overlay
focused on tenant-specific guidance and local/data-workflow entrypoints.

## Do Not Duplicate Here
Expand Down
4 changes: 2 additions & 2 deletions templates/tenant-overlay/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ This docs index is intentionally thin.
- Use `sources/devkit/docs/README.md` for shared DX/runtime/bootstrap docs.
- Use the generated tenant-root run configurations when you need to call the
current runtime commands in the sibling `odoo-devkit` repo.
- Use `harbor` for remote release actions such as ship, promote,
- Use `launchplane` for remote release actions such as ship, promote,
and gate execution. Stable remote lanes are `testing` and `prod`; PR
previews belong to Harbor preview workflows instead of a durable `dev` lane.
previews belong to Launchplane preview workflows instead of a durable `dev` lane.
- Keep this tenant docs tree focused on tenant-owned domain workflows,
architecture notes, and operational quirks.

Expand Down
17 changes: 9 additions & 8 deletions templates/workspace-cockpit/workspace-cockpit.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ plans_directory = "~/.codex/plans"
[guidance.agents]
first_reads = [
"Open [docs/README.md](docs/README.md) in this workspace root first.",
"If present, open [AGENTS.override.md](AGENTS.override.md) for local, non-secret operator details before touching infra, SSH, tunnels, or remote service configuration.",
"Use [sources/devkit/AGENTS.md](sources/devkit/AGENTS.md) for the canonical shared operating guide.",
"Use [sources/devkit/docs/README.md](sources/devkit/docs/README.md) for the canonical shared docs index.",
"Use the tenant-specific `workspace.toml` manifests when you need to run current local runtime commands through `odoo-devkit`.",
]
ownership = [
"`odoo-devkit` owns shared DX/runtime/workspace behavior plus local runtime and explicit data workflows.",
"`harbor` owns remote release actions, deployment truth, release tuples, and promotion evidence.",
"`launchplane` owns remote release actions, deployment truth, release tuples, and promotion evidence.",
"Stable remote lanes are `testing` and `prod`.",
"Harbor PR previews replace any durable shared `dev` lane.",
"Launchplane PR previews replace any durable shared `dev` lane.",
]
notes = [
"This cockpit root is regenerated from `workspace-cockpit.toml` through `odoo-devkit`; keep the repo map and root guidance in that config instead of hand-editing markdown entrypoints.",
Expand All @@ -28,9 +29,9 @@ external_reference_boundary = [
]
working_split = [
"Use `odoo-devkit` for shared DX/runtime/workspace behavior and for local runtime plus explicit data workflows.",
"Use `harbor` for remote release actions, deployment truth, release tuples, and promotion evidence.",
"Use `launchplane` for remote release actions, deployment truth, release tuples, and promotion evidence.",
"Stable remote lanes are `testing` and `prod`.",
"Harbor PR previews replace any durable shared `dev` lane.",
"Launchplane PR previews replace any durable shared `dev` lane.",
]
operational_notes = [
"Historical plans remain available under `/Users/cbusillo/.codex/plans/` when you need rationale or prior sequencing.",
Expand All @@ -40,9 +41,9 @@ operational_notes = [
working_rules = [
"Treat repos under sources/ as the primary system under construction.",
"Use odoo-devkit for shared DX/runtime/workspace behavior and local/data workflows.",
"Use harbor for remote release actions, deployment truth, release tuples, and promotion evidence.",
"Use launchplane for remote release actions, deployment truth, release tuples, and promotion evidence.",
"Stable remote lanes are testing and prod.",
"Harbor PR previews replace any durable shared dev lane.",
"Launchplane PR previews replace any durable shared dev lane.",
"Do not bring odoo-ai into the normal workspace context unless the task is explicit archaeology.",
"Keep tenant repos thin and tenant-specific; fix shared behavior in devkit.",
"When `workspace-cockpit.toml`, the workspace root, and source repos disagree, treat the source repos as the source of truth, then regenerate the cockpit.",
Expand Down Expand Up @@ -80,8 +81,8 @@ repo_name = "odoo-tenant-opw"
group = "primary"
role = "control_plane"
label = "Control plane"
path = "sources/harbor"
repo_name = "harbor"
path = "sources/launchplane"
repo_name = "launchplane"

[[repos]]
group = "upstream_image"
Expand Down
9 changes: 7 additions & 2 deletions tests/test_scaffold.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ def test_scaffold_writes_workspace_cockpit_manifest_and_generated_docs(self) ->

self.assertIn("schema_version = 1", manifest_text)
self.assertIn("workspace-cockpit.toml", agents_text)
self.assertIn("AGENTS.override.md", agents_text)
self.assertIn("sources/devkit", agents_text)
self.assertIn("sync-cockpit-root", docs_index_text)
self.assertIn("status-cockpit-root", docs_index_text)
Expand Down Expand Up @@ -202,12 +203,14 @@ def test_real_workspace_cockpit_template_links_back_to_devkit(self) -> None:
self.assertIn("[guidance.session_prompt]", manifest_text)
self.assertIn("sources/devkit/AGENTS.md", agents_text)
self.assertIn("sources/devkit/docs/README.md", agents_text)
self.assertIn("AGENTS.override.md", agents_text)
self.assertIn("Shared operating guide", docs_index_text)
self.assertIn("Shared workspace CLI guide", docs_index_text)
self.assertIn("workspace-cockpit.toml", agents_text)
self.assertIn("uv --project sources/devkit", agents_text)
self.assertIn("status-cockpit-root", agents_text)
self.assertIn("workspace root, and source repos", session_prompt_text)
self.assertIn("harbor for remote release actions", session_prompt_text)
self.assertIn("launchplane for remote release actions", session_prompt_text)


class WorkspaceCockpitSyncTests(unittest.TestCase):
Expand Down Expand Up @@ -265,7 +268,9 @@ def test_sync_workspace_cockpit_rerenders_existing_root(self) -> None:

self.assertEqual(result.output_directory, output_directory)
self.assertIn(output_directory / "AGENTS.md", result.written_paths)
self.assertIn("sources/shared-addons", (output_directory / "AGENTS.md").read_text(encoding="utf-8"))
agents_text = (output_directory / "AGENTS.md").read_text(encoding="utf-8")
self.assertIn("sources/shared-addons", agents_text)
self.assertIn("AGENTS.override.md", agents_text)
self.assertIn("Public base image", (output_directory / "docs" / "README.md").read_text(encoding="utf-8"))
self.assertIn("source repos as the source of truth", (output_directory / "docs" / "session-prompt.md").read_text(encoding="utf-8"))

Expand Down
Loading
Loading