commits
The sync workflow is:
1. Push: mono/ → local src/ (subtree push to checkout_dir)
2. Pull: local src/ → mono/ (subtree pull from checkout_dir)
Previously, step 2 was pulling from the remote URL (Package.dev_repo),
which could have different commits than the local checkout, causing
conflicts when the remote was out of sync.
Now both push and pull use the same local checkout as the source of
truth, ensuring the round-trip is consistent.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Git_config action and set receive.denyCurrentBranch=updateInstead
on newly created src/ repos. This allows monopam sync to push changes
from mono/ to the src/ checkout without git refusing.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Don't add sources.toml entries when the push URL is in the user's own
namespace (same handle). Only track entries when forking from someone
else's repository.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous replacement logic was broken - it was mangling the string
by splitting on 'S' instead of replacing the literal "SPLIT_COMMIT".
Simplified to a straightforward prefix check and substring replacement.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add suggest_push_url function to derive push URL from dune-project source field
- Support github, gitlab, tangled, and uri sources
- Convert https URLs to SSH push format (git@...)
- Prompt with suggested URL as default, user can press Enter to accept
- Fix pp_fork_result to not truncate non-SHA strings like "(fresh package)"
- Add Tangled variant to Dune_project.source_info for tangled.sh sources
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Prompt for remote push URL if not provided on command line
(skipped with --yes or --dry-run)
- Fix pp_fork_result to only truncate git SHA hashes (40 hex chars),
not descriptive strings like "(fresh package)"
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fork now performs the complete workflow in one command:
- Creates src/<name>/ with split history or copied files
- Removes mono/<name>/ from git
- Re-adds mono/<name>/ as a proper subtree from src/<name>/
This establishes the subtree relationship automatically so monopam sync
works correctly without manual git rm and rejoin steps.
Added Git.rm function for git rm operations.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fork/join improvements:
- Add action planning system that analyzes state before execution
- Show discovery details (subtree history, packages found, etc.)
- Prompt for confirmation with --yes flag to skip
- Support fresh package fork (no subtree history) by copying files
- Support join from local directories (not just URLs)
- Add Git.add_all, Git.commit, Git.branch_rename, Git.has_subtree_history
Config unification:
- Merge Verse_config into Config module
- Add configurable paths (mono, src, verse) in [paths] section
- Verse_config is now an alias for backwards compatibility
- Simplify main.ml config loading
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Monorepo_dirty error that is returned early in the sync function
if the monorepo working tree has uncommitted changes. This prevents
confusion and potential data loss from syncing with a dirty state.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The needs_pull optimization was computed from status before fetching
from remotes. If a repo was "In_sync" but received commits during
fetch, it was incorrectly skipped in the subtree pull phase.
Now repos that receive commits during fetch are always included in
the subtree pull, regardless of their pre-fetch status.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The push phase checked status to skip already-synced repos, but the
subtree pull phase didn't - it pulled ALL repos unconditionally with
--squash, creating new merge commits even when already in sync. This
caused conflicts on subsequent syncs.
Add needs_pull check that skips subtree pulls when:
- In_sync: trees match, nothing to do
- Subtree_ahead: monorepo is ahead, need push not pull
- Unknown: can't determine, conservative skip
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add `monopam init` as top-level command (previously `monopam verse init`)
- Integrate verse pull into `monopam sync` when verse config exists
- Simplify `monopam verse` to only include `members` and `fork` subcommands
- Update all error hints and help text to reference `monopam init`
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove all references to 'tangled auth login' (no longer needed)
- Replace 'monopam push' references with 'monopam sync' workflow
- Update verse quick start to remove authentication step
- Replace AUTHENTICATION sections with HANDLES/HANDLE VALIDATION
- Document --skip-push and --skip-pull for finer control
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a new Site module that generates a static index.html showing:
- All verse members with links to their repos
- Summary of common libraries and member-specific packages
- Detailed repository information with fork status
Also extends verse_registry to support name field for members
and description field for registries.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When --url is provided without --from, use the URL for cloning
and treat the positional argument as the subtree name.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements fork/join operations for unified source management:
- fork: Split a monorepo subtree into its own repo in src/
Uses git subtree split to extract history and creates standalone repo
Updates sources.toml with origin = "fork"
- join: Bring an external repo into the monorepo as a subtree
Clones to src/ and uses git subtree add
Supports --from for joining from verse members
Updates sources.toml with origin = "join"
Also adds:
- origin type to Sources_registry for tracking source provenance
- push_ref helper to Git module
- Origin indicators (^ for fork, v:handle for join) in status output
- Fork_join module with full implementation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove unused dev_repo field from Package_config and package_override
types. URL overrides are now handled by sources.toml in the monorepo
root, making the per-package dev_repo in opamverse.toml redundant.
- Add clone_from_verse_if_needed to enable monopam sync to work in
fresh devcontainers by cloning monorepo and opam-repo from verse
registry if they don't exist locally.
- Update documentation to clarify that sources.toml is the single source
of truth for URL overrides, while opamverse.toml only handles branch
overrides.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add --url option to override devcontainer.json source URL
- Update main CLI help to recommend starting with devcontainer
- Add note that monopam is designed to run in a devcontainer
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Creates and enters a devcontainer environment for OCaml development:
- If .devcontainer/ doesn't exist: creates directory structure,
fetches devcontainer.json from claude-ocaml-devcontainer template,
builds and starts the container
- If .devcontainer/ exists: starts the container if needed and
opens an interactive bash shell
Usage: monopam devcontainer <path>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add upstream_url and subtree_name to fork_result type
- Extract subtree name from fork URL (last path component)
- Automatically update sources.toml with fork entry containing:
- url: the user's fork URL
- upstream: original dev-repo URL from source package
- reason: "Forked from <handle>"
This ensures sync uses the correct URLs for forked packages.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove domain_from_handle (no longer guess knot from handles)
- For tangled URLs, default to git.recoil.org unless knot is provided
- Support both tangled.org and tangled.sh hosts
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add is_tangled_host function to handle both tangled.org and tangled.sh
- Fix domain_from_handle to require 2 dots (user.domain.tld format)
- Handles like "gazagnaire.org" now return the full handle instead of
incorrectly extracting "org" as the domain
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When pushing from monorepo subtrees to local checkouts, git refuses
to update a checked-out branch by default. This configures checkouts
with receive.denyCurrentBranch=updateInstead, which allows pushes and
automatically updates the working tree.
Applied to both new clones and existing checkouts during sync.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The sync command was using stale URLs from the opam-repo instead of
the authoritative URLs from the monorepo's dune-project files. This
caused clone failures for repos where the opam-repo had outdated
dev-repo URLs (e.g., ocaml-peertube had git.recoil.org instead of
tangled.org).
Now sync regenerates opam-repo entries from the monorepo before
discovering packages, ensuring URLs are always up to date.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The verse remotes phase and remote push phase were using the full
`repos` list instead of `successfully_fetched_repos`, causing crashes
when trying to access checkout directories that don't exist due to
failed clones.
Now both phases only operate on repos that were successfully cloned
or fetched, preventing "No such file or directory" errors.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Git operations:
- Add retry logic with exponential backoff for HTTP 5xx errors
- Retry on RPC failures, curl errors, connection issues
- 3 retries with 2s/4s/8s delays before failing
- Apply to clone, fetch, pull, push, and subtree operations
Sources registry (sources.toml):
- New module for tracking package URL overrides
- default_url_base for deriving URLs from subtree names
- Per-package entries with url, upstream, branch, reason
Verse config:
- Add knot field for git push server (e.g., "git.recoil.org")
- Default to "git.recoil.org" if not present in config
- Auto-write knot to config file if missing
URL handling:
- Remove hardcoded anil.recoil.org references
- Derive git push server from handle or use configured knot
- Generic SSH URL normalization in forks.ml
Sync resilience:
- Skip failed clones in merge/subtree phases instead of crashing
- Track successfully fetched repos separately from failures
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This is more compatible with opam conventions - dev-repo is just the
repository URL, while the url field's src can include a #branch fragment.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Local git subtree push operations don't need a parallelism limit since
they only write to the local filesystem. Network operations (fetch,
remote push) still have limits to avoid overwhelming remote servers.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The diff-based approach broke the convergence invariant by creating
synthetic "Sync X from monorepo" commits instead of preserving original
commit identity. This caused repeated syncs to never converge as each
sync created new commits.
Using git subtree push preserves commit history, ensuring that changes
pushed to checkouts can be recognized as the same commits when pulled
back via subtree pull. The push phase still runs with max_fibers:4.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
# Conflicts:
# monopam/lib/forks.ml
# monopam/lib/forks.mli
# monopam/lib/git.ml
# monopam/lib/git.mli
# monopam/lib/monopam.mli
The previous 5-minute cache was expiring too quickly during typical
development workflows. An hour-long cache reduces redundant fetches
while still keeping data reasonably fresh. Use --refresh to force
fresh fetches when needed.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- `monopam pull <handle> [repo]`: Pull commits from a verse member's
forks into local checkouts. Merges their changes (fast-forward when
possible, merge commit when diverged).
- `monopam cherrypick <sha>`: Apply a specific commit from a verse
member's fork to the appropriate local checkout.
Both commands integrate with the existing diff command workflow:
1. monopam diff - see available changes
2. monopam pull/cherrypick - apply changes
3. monopam sync - merge into monorepo
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add -p flag to show full patch content for each commit
- Support `monopam diff <sha>` to show patch for specific commit from diff output
- Add Git.show_patch for fetching commit patches
- Detect commit SHA vs repo name (7+ hex characters)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- New `monopam diff` command shows commits from verse members for
repos needing attention (where they are ahead or diverged)
- Implements 5-minute fetch cache to avoid repeated remote fetches
- Cache stored in ~/.cache/monopam/fetch-cache.json
- Use --refresh to force fresh fetches
- Shows commit list with hash, subject, and author
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When the dev-repo field contains a URL fragment like #staging or #master,
extract it and use it as the package's branch. This allows specifying
branches in opam files rather than relying on config overrides.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Uri.to_string percent-encodes special characters like @, which breaks
SSH URLs like git@host:path. Use Uri.pct_decode to restore the original
URL string.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Similar to the merge step fix, fetch_verse_remotes was calling
Git.list_remotes without checking if the checkout exists first.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The merge step was iterating over all packages without checking if
the checkout directory exists, causing an Eio.Io Fs Not_found error
for packages like dune, odoc, etc. that don't have local checkouts.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds 'monopam feature add/remove/list' commands that create git worktrees
in root/work/<name> on branch <name>, enabling multiple Claude instances
to work on different features simultaneously.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Registry member URLs can now include a #branch suffix to specify a
non-default branch (e.g., "https://github.com/user/repo#develop").
Also changes verse pull to use fetch+reset instead of pull, since verse
repos should not have local modifications.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
git subtree push is slow because it walks the entire repository history
to reconstruct commits. For large repos, this is O(commits) which can
take minutes.
Replace with a diff-based approach that is O(changed files):
1. Generate diff between monorepo subtree and checkout using
git diff --no-index
2. Apply the diff to checkout using git apply
3. Stage and commit the changes
Also parallelize remote push using Eio.Fiber.List.map with max_fibers:2.
- Use pattern match for gitdir parsing instead of String.sub
- Use List.filter_map instead of filter + map
- Simplify empty string check (s <> "" vs String.length)
New command: monopam verse fork <package> --from <handle> --url <fork-url>
This allows users to fork a package from a verse member's repository:
- Looks up the package in verse/<handle>-opam/
- Finds all packages sharing the same git repository
- Creates entries in user's opam-repo with fork URL as dev-repo
- Supports --dry-run to preview what would be forked
- Detects conflicts if packages already exist in user's opam-repo
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add --no-sync flag to skip the pre-analysis sync
- Run monopam sync before doctor analysis by default
- Include formatted monopam status output in Claude prompt
- Tell Claude it doesn't need to run status/sync itself
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove max_turns=1 restriction and plan mode to allow Claude to use
tools for deeper analysis. Add a custom handler that streams tool
usage to the console so users can see what Claude is doing:
- Bash commands (truncated to 60 chars)
- Read file paths
- Grep/Glob patterns
- Other tool names
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
# Conflicts:
# monopam/lib/doctor.ml
- Add git fetch --all to sync: fetches all remotes (including verse
remotes) instead of just origin
- Add Git.fetch_all and Git.log_range functions
- Rewrite doctor command to be more useful:
- Analyzes all remotes in each src/ directory
- Collects commits from remotes where we're behind
- Builds comprehensive status summary for Claude prompt
- Sends single prompt to Claude for holistic analysis
- Returns actionable recommendations
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Limits parallel network operations to avoid overwhelming remotes:
- Push to checkouts: max 4 concurrent
- Fetch from remotes: max 4 concurrent
- Fetch verse remotes: max 4 concurrent
Remote push was already limited to 2 concurrent operations.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When syncing opam metadata, now detects packages that exist in the
opam-repo overlay but have no corresponding subtree in the monorepo.
These are reported as warnings with a suggestion to manually remove
them from opam-repo/packages/.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements `monopam doctor` for workspace health analysis:
- Checks local sync status (monorepo vs checkouts)
- Checks remote sync status (checkouts vs upstream)
- Analyzes fork relationships with verse members
- Uses Claude AI to categorize and prioritize verse commits
- Generates actionable recommendations
Features:
- Commit categorization: security-fix, bug-fix, feature, refactor, docs, test
- Priority levels: critical, high, medium, low
- Recommendations: merge-now, review-first, skip, needs-discussion
- Conflict risk assessment
Output formats:
- Human-readable text with colors (default)
- JSON output with --json flag
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The sync workflow is:
1. Push: mono/ → local src/ (subtree push to checkout_dir)
2. Pull: local src/ → mono/ (subtree pull from checkout_dir)
Previously, step 2 was pulling from the remote URL (Package.dev_repo),
which could have different commits than the local checkout, causing
conflicts when the remote was out of sync.
Now both push and pull use the same local checkout as the source of
truth, ensuring the round-trip is consistent.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add suggest_push_url function to derive push URL from dune-project source field
- Support github, gitlab, tangled, and uri sources
- Convert https URLs to SSH push format (git@...)
- Prompt with suggested URL as default, user can press Enter to accept
- Fix pp_fork_result to not truncate non-SHA strings like "(fresh package)"
- Add Tangled variant to Dune_project.source_info for tangled.sh sources
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fork now performs the complete workflow in one command:
- Creates src/<name>/ with split history or copied files
- Removes mono/<name>/ from git
- Re-adds mono/<name>/ as a proper subtree from src/<name>/
This establishes the subtree relationship automatically so monopam sync
works correctly without manual git rm and rejoin steps.
Added Git.rm function for git rm operations.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fork/join improvements:
- Add action planning system that analyzes state before execution
- Show discovery details (subtree history, packages found, etc.)
- Prompt for confirmation with --yes flag to skip
- Support fresh package fork (no subtree history) by copying files
- Support join from local directories (not just URLs)
- Add Git.add_all, Git.commit, Git.branch_rename, Git.has_subtree_history
Config unification:
- Merge Verse_config into Config module
- Add configurable paths (mono, src, verse) in [paths] section
- Verse_config is now an alias for backwards compatibility
- Simplify main.ml config loading
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The needs_pull optimization was computed from status before fetching
from remotes. If a repo was "In_sync" but received commits during
fetch, it was incorrectly skipped in the subtree pull phase.
Now repos that receive commits during fetch are always included in
the subtree pull, regardless of their pre-fetch status.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The push phase checked status to skip already-synced repos, but the
subtree pull phase didn't - it pulled ALL repos unconditionally with
--squash, creating new merge commits even when already in sync. This
caused conflicts on subsequent syncs.
Add needs_pull check that skips subtree pulls when:
- In_sync: trees match, nothing to do
- Subtree_ahead: monorepo is ahead, need push not pull
- Unknown: can't determine, conservative skip
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add `monopam init` as top-level command (previously `monopam verse init`)
- Integrate verse pull into `monopam sync` when verse config exists
- Simplify `monopam verse` to only include `members` and `fork` subcommands
- Update all error hints and help text to reference `monopam init`
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove all references to 'tangled auth login' (no longer needed)
- Replace 'monopam push' references with 'monopam sync' workflow
- Update verse quick start to remove authentication step
- Replace AUTHENTICATION sections with HANDLES/HANDLE VALIDATION
- Document --skip-push and --skip-pull for finer control
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a new Site module that generates a static index.html showing:
- All verse members with links to their repos
- Summary of common libraries and member-specific packages
- Detailed repository information with fork status
Also extends verse_registry to support name field for members
and description field for registries.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements fork/join operations for unified source management:
- fork: Split a monorepo subtree into its own repo in src/
Uses git subtree split to extract history and creates standalone repo
Updates sources.toml with origin = "fork"
- join: Bring an external repo into the monorepo as a subtree
Clones to src/ and uses git subtree add
Supports --from for joining from verse members
Updates sources.toml with origin = "join"
Also adds:
- origin type to Sources_registry for tracking source provenance
- push_ref helper to Git module
- Origin indicators (^ for fork, v:handle for join) in status output
- Fork_join module with full implementation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove unused dev_repo field from Package_config and package_override
types. URL overrides are now handled by sources.toml in the monorepo
root, making the per-package dev_repo in opamverse.toml redundant.
- Add clone_from_verse_if_needed to enable monopam sync to work in
fresh devcontainers by cloning monorepo and opam-repo from verse
registry if they don't exist locally.
- Update documentation to clarify that sources.toml is the single source
of truth for URL overrides, while opamverse.toml only handles branch
overrides.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Creates and enters a devcontainer environment for OCaml development:
- If .devcontainer/ doesn't exist: creates directory structure,
fetches devcontainer.json from claude-ocaml-devcontainer template,
builds and starts the container
- If .devcontainer/ exists: starts the container if needed and
opens an interactive bash shell
Usage: monopam devcontainer <path>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add upstream_url and subtree_name to fork_result type
- Extract subtree name from fork URL (last path component)
- Automatically update sources.toml with fork entry containing:
- url: the user's fork URL
- upstream: original dev-repo URL from source package
- reason: "Forked from <handle>"
This ensures sync uses the correct URLs for forked packages.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add is_tangled_host function to handle both tangled.org and tangled.sh
- Fix domain_from_handle to require 2 dots (user.domain.tld format)
- Handles like "gazagnaire.org" now return the full handle instead of
incorrectly extracting "org" as the domain
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When pushing from monorepo subtrees to local checkouts, git refuses
to update a checked-out branch by default. This configures checkouts
with receive.denyCurrentBranch=updateInstead, which allows pushes and
automatically updates the working tree.
Applied to both new clones and existing checkouts during sync.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The sync command was using stale URLs from the opam-repo instead of
the authoritative URLs from the monorepo's dune-project files. This
caused clone failures for repos where the opam-repo had outdated
dev-repo URLs (e.g., ocaml-peertube had git.recoil.org instead of
tangled.org).
Now sync regenerates opam-repo entries from the monorepo before
discovering packages, ensuring URLs are always up to date.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The verse remotes phase and remote push phase were using the full
`repos` list instead of `successfully_fetched_repos`, causing crashes
when trying to access checkout directories that don't exist due to
failed clones.
Now both phases only operate on repos that were successfully cloned
or fetched, preventing "No such file or directory" errors.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Git operations:
- Add retry logic with exponential backoff for HTTP 5xx errors
- Retry on RPC failures, curl errors, connection issues
- 3 retries with 2s/4s/8s delays before failing
- Apply to clone, fetch, pull, push, and subtree operations
Sources registry (sources.toml):
- New module for tracking package URL overrides
- default_url_base for deriving URLs from subtree names
- Per-package entries with url, upstream, branch, reason
Verse config:
- Add knot field for git push server (e.g., "git.recoil.org")
- Default to "git.recoil.org" if not present in config
- Auto-write knot to config file if missing
URL handling:
- Remove hardcoded anil.recoil.org references
- Derive git push server from handle or use configured knot
- Generic SSH URL normalization in forks.ml
Sync resilience:
- Skip failed clones in merge/subtree phases instead of crashing
- Track successfully fetched repos separately from failures
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The diff-based approach broke the convergence invariant by creating
synthetic "Sync X from monorepo" commits instead of preserving original
commit identity. This caused repeated syncs to never converge as each
sync created new commits.
Using git subtree push preserves commit history, ensuring that changes
pushed to checkouts can be recognized as the same commits when pulled
back via subtree pull. The push phase still runs with max_fibers:4.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- `monopam pull <handle> [repo]`: Pull commits from a verse member's
forks into local checkouts. Merges their changes (fast-forward when
possible, merge commit when diverged).
- `monopam cherrypick <sha>`: Apply a specific commit from a verse
member's fork to the appropriate local checkout.
Both commands integrate with the existing diff command workflow:
1. monopam diff - see available changes
2. monopam pull/cherrypick - apply changes
3. monopam sync - merge into monorepo
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- New `monopam diff` command shows commits from verse members for
repos needing attention (where they are ahead or diverged)
- Implements 5-minute fetch cache to avoid repeated remote fetches
- Cache stored in ~/.cache/monopam/fetch-cache.json
- Use --refresh to force fresh fetches
- Shows commit list with hash, subject, and author
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Registry member URLs can now include a #branch suffix to specify a
non-default branch (e.g., "https://github.com/user/repo#develop").
Also changes verse pull to use fetch+reset instead of pull, since verse
repos should not have local modifications.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
git subtree push is slow because it walks the entire repository history
to reconstruct commits. For large repos, this is O(commits) which can
take minutes.
Replace with a diff-based approach that is O(changed files):
1. Generate diff between monorepo subtree and checkout using
git diff --no-index
2. Apply the diff to checkout using git apply
3. Stage and commit the changes
Also parallelize remote push using Eio.Fiber.List.map with max_fibers:2.
New command: monopam verse fork <package> --from <handle> --url <fork-url>
This allows users to fork a package from a verse member's repository:
- Looks up the package in verse/<handle>-opam/
- Finds all packages sharing the same git repository
- Creates entries in user's opam-repo with fork URL as dev-repo
- Supports --dry-run to preview what would be forked
- Detects conflicts if packages already exist in user's opam-repo
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove max_turns=1 restriction and plan mode to allow Claude to use
tools for deeper analysis. Add a custom handler that streams tool
usage to the console so users can see what Claude is doing:
- Bash commands (truncated to 60 chars)
- Read file paths
- Grep/Glob patterns
- Other tool names
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add git fetch --all to sync: fetches all remotes (including verse
remotes) instead of just origin
- Add Git.fetch_all and Git.log_range functions
- Rewrite doctor command to be more useful:
- Analyzes all remotes in each src/ directory
- Collects commits from remotes where we're behind
- Builds comprehensive status summary for Claude prompt
- Sends single prompt to Claude for holistic analysis
- Returns actionable recommendations
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements `monopam doctor` for workspace health analysis:
- Checks local sync status (monorepo vs checkouts)
- Checks remote sync status (checkouts vs upstream)
- Analyzes fork relationships with verse members
- Uses Claude AI to categorize and prioritize verse commits
- Generates actionable recommendations
Features:
- Commit categorization: security-fix, bug-fix, feature, refactor, docs, test
- Priority levels: critical, high, medium, low
- Recommendations: merge-now, review-first, skip, needs-discussion
- Conflict risk assessment
Output formats:
- Human-readable text with colors (default)
- JSON output with --json flag
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>