Skip to content

feat: project-tier toolchain (ocx.toml + ocx.lock)#67

Open
michael-herwig wants to merge 1 commit intomainfrom
feat/project-toolchain
Open

feat: project-tier toolchain (ocx.toml + ocx.lock)#67
michael-herwig wants to merge 1 commit intomainfrom
feat/project-toolchain

Conversation

@michael-herwig
Copy link
Copy Markdown
Contributor

Summary

  • Project-tier toolchain config: ocx.toml + ocx.lock with sidecar exclusive lock for safe concurrent writes
  • Project-toolchain CLI commands and pull UX, plus shell activation stack (push/pop layered envs)
  • Index routing fix: explicit IndexOperation::{Query, Resolve} threaded through IndexImpl; pinned-id pulls skip tag-pointer commit; --offline --remote accepted as pinned-only mode
  • Website fix: catalog generation no longer leaks local-index writes (workaround dropped after routing fix)

Commits

  • 60c9c0f feat(project)!: project-tier toolchain config (ocx.toml + ocx.lock)
  • 7f81111 feat(project): add load_exclusive sidecar lock for ocx.lock writes
  • 06257c8 feat(cli): project-toolchain commands and pull UX
  • 8a2acf2 feat(cli): shell activation stack for project toolchain
  • 8b2b626 fix(website): unbreak catalog generation in build pipeline
  • 6f8f8ec fix(oci): explicit IndexOperation routing + pinned-id tag-skip

Breaking change: project-tier config (see 60c9c0f).

Test plan

  • task verify green on CI
  • Acceptance suite: test_project_config, test_project_pull, test_lock, test_shell_hook, test_shell_profile{,_generate}, test_generate_direnv, test_pinned_offline, test_doc_project_toolchain, test_taplo_project_toolchain, test_exec_compose, test_index, test_update, test_schema_generation
  • Unit test op_query_never_walks_source_in_any_mode passes
  • Unit test pinned_id_pull_skips_tag_pointer_commit passes
  • Acceptance test_remote_index_list_does_not_write_local_tags passes (filesystem byte-equality)
  • Acceptance test_pinned_id_exec_offline_succeeds passes (lock + pull + offline exec)
  • Manual: ocx index list <pkg>@<digest> rejected with usage error
  • Manual: --offline --remote runs with info log, no registry contact
  • Website build: catalog generation succeeds without unset OCX_INDEX workaround

Docs

  • ADR: adr_index_routing_semantics.md
  • Updated: subsystem-oci.md, subsystem-cli.md, subsystem-cli-commands.md, CLAUDE.md
  • User guide: Routing subsection + Pinned-only mode
  • Reference: command-line.md, environment.md, configuration.md, user-guide.md

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 28, 2026

Unit Test Results

1 559 tests  +198   1 559 ✅ +198   14s ⏱️ +2s
    4 suites +  1       0 💤 ±  0 
    1 files   ±  0       0 ❌ ±  0 

Results for commit 817c4a3. ± Comparison against base commit 43d3f2d.

This pull request removes 16 and adds 214 tests. Note that renamed tests count towards both.
ocx_lib ‑ profile::snapshot::tests::content_digests_ignores_non_content_entries
ocx_lib ‑ profile::snapshot::tests::content_digests_returns_identifiers_with_digest
ocx_lib ‑ profile::snapshot::tests::content_digests_skips_entries_without_digest
ocx_lib ‑ profile::snapshot::tests::empty_snapshot_has_no_entries
ocx_lib ‑ profile::snapshot::tests::load_missing_file_returns_empty
ocx_lib ‑ profile::tests::add_duplicate_updates_mode
ocx_lib ‑ profile::tests::contains_check
ocx_lib ‑ profile::tests::content_digest_on_identifier_roundtrip
ocx_lib ‑ profile::tests::default_manifest_has_version_1
ocx_lib ‑ profile::tests::load_exclusive_prevents_concurrent_lock
…
ocx::bin/ocx ‑ api::tests::report_renders_plain_when_not_quiet
ocx::bin/ocx ‑ api::tests::report_skips_json_when_quiet
ocx::bin/ocx ‑ api::tests::report_skips_render_when_quiet
ocx_lib ‑ cli::classify::tests::project_file_not_found_error_message_points_at_project_flag
ocx_lib ‑ cli::classify::tests::project_file_not_found_maps_to_not_found
ocx_lib ‑ config::loader::tests::project_path_empty_env_var_treated_as_unset
ocx_lib ‑ config::loader::tests::project_path_env_var_loads_valid_file
ocx_lib ‑ config::loader::tests::project_path_env_var_missing_file_returns_not_found
ocx_lib ‑ config::loader::tests::project_path_explicit_accepts_any_basename
ocx_lib ‑ config::loader::tests::project_path_explicit_directory_rejected_as_io
…

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 28, 2026

Acceptance Test Results

496 tests  +80   483 ✅ +77   4m 16s ⏱️ + 2m 34s
  1 suites ± 0    13 💤 + 3 
  1 files   ± 0     0 ❌ ± 0 

Results for commit 817c4a3. ± Comparison against base commit 43d3f2d.

This pull request removes 61 and adds 141 tests. Note that renamed tests count towards both.
tests.test_exec_modes ‑ test_all_surfaces_carry_self_flag[surface5---self]
tests.test_exec_modes ‑ test_all_surfaces_carry_self_flag[surface5-None]
tests.test_shell_profile ‑ test_clean_protects_profiled_content_objects
tests.test_shell_profile ‑ test_deselect_warns_about_profile
tests.test_shell_profile ‑ test_profile_add_auto_installs
tests.test_shell_profile ‑ test_profile_add_auto_installs_candidate
tests.test_shell_profile ‑ test_profile_add_auto_installs_content
tests.test_shell_profile ‑ test_profile_add_auto_installs_offline_fails
tests.test_shell_profile ‑ test_profile_add_bare_name_as_latest
tests.test_shell_profile ‑ test_profile_add_candidate
…
tests.test_clean_project_backlinks ‑ test_force_does_not_collect_actively_installed_packages
tests.test_clean_project_backlinks ‑ test_force_flag_bypasses_registry
tests.test_clean_project_backlinks ‑ test_lazy_prune_after_lockfile_deletion
tests.test_clean_project_backlinks ‑ test_package_held_by_other_project_survives_clean
tests.test_doc_command_reference ‑ test_command_reference_has_no_phase10_todo_markers
tests.test_doc_command_reference ‑ test_lock_section_has_exit_code_table
tests.test_doc_command_reference ‑ test_lock_section_mentions_declaration_hash
tests.test_doc_command_reference ‑ test_lock_section_mentions_ocx_lock_filename
tests.test_doc_command_reference ‑ test_new_command_anchor_present[{#generate-direnv}-generate direnv]
tests.test_doc_command_reference ‑ test_new_command_anchor_present[{#generate}-generate]
…

♻️ This comment has been updated with latest results.

Introduce a project-tier toolchain layer. Drop an `ocx.toml` next to a
project, declare tool versions, and `ocx pull` / `ocx add <tool>` /
`ocx remove <tool>` / `ocx init` keep `ocx.lock` in sync with chosen
tags resolved to digests. Shell integration (`ocx shell hook`,
`ocx shell direnv`) activates and deactivates the locked toolchain
when entering/leaving the project tree.

Highlights:

- `ocx.toml` schema with `[tools]` table; bare identifiers default to
  `:latest`. `ocx.lock` records resolved digest + manifest sources
  consumed by `ocx pull --project`.
- New CLI verbs: `ocx init`, `ocx add`, `ocx remove`, `ocx update`,
  `ocx lock`. `ocx pull` learns `--project` and `--group` filters with
  symmetric progress reporting.
- Shell activation stack — entering nested project trees layers the
  project toolchain on top of the parent's; leaving on exit reverts.
- `ocx shell hook` / `ocx shell direnv` emit bash/zsh exports keyed on
  a fingerprint, reused across PROMPT_COMMAND / direnv invocations.
- `--project` flag (and `OCX_PROJECT` env) forwarded through
  `OcxConfigView` so child ocx invocations inherit the parent's
  project selection. `OCX_NO_PROJECT` / `OCX_NO_CONFIG` env kill-
  switches for discovery.
- Project registry retains `ocx.lock` backlinks; `ocx clean` walks
  reachability through registered project locks.
- Atomic `ocx.lock` writes use a `.ocx-lock` sentinel; advisory
  `ocx.lock.lock` sidecar removed.
- Index routing: explicit `IndexOperation` selection separates
  network-hitting lookups from pinned-id lookups that skip tag refresh.

Dogfoods its own toolchain: cmake, shellcheck, shfmt pinned under
`.ocx/index/ocx.sh/`; `ocx.toml` at repo root declares dev-tool
versions used by `task verify`.

BREAKING CHANGES:

- `profile` library module and `ocx shell profile` CLI surface
  removed. Project toolchains supersede shell profiles. Migration:
  declare tools in `ocx.toml` and rely on `ocx shell hook` /
  `ocx shell direnv` for activation.
- `ocx hook-env` removed. Use `ocx shell hook`.
- `ocx exec --group` and the `[name=]identifier` positional alias
  removed. Exec pinned identifiers directly, or rely on shell-hook
  activation.
- `ocx.lock` advisory locking now uses `.ocx-lock` sentinel file.
  External readers of the prior `ocx.lock.lock` sidecar must switch.
@michael-herwig michael-herwig force-pushed the feat/project-toolchain branch from 6f8f8ec to 817c4a3 Compare May 3, 2026 16:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant