Skip to content

Add <Repository>, <Worktree>, <Issue>, and <PullRequest> to xmd run - #689

Closed
taras wants to merge 5 commits into
mainfrom
agent/issue-643-run-repositories
Closed

Add <Repository>, <Worktree>, <Issue>, and <PullRequest> to xmd run#689
taras wants to merge 5 commits into
mainfrom
agent/issue-643-run-repositories

Conversation

@taras

@taras taras commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Closes #643.

Why

An ordinary xmd run could not use the repository components. A document could launch an Agent, but it could not create a worktree for that Agent, operate on Git, read or update an issue, or publish a pull request without becoming a retained workflow.

This prevented documents such as the roles in AGENTS.md from expressing the repository work they need to perform.

What changes

Before:

<Repository>, <Worktree>, <Dir>, the Git.* components, <Issue>, and the PullRequest.* components resolved only inside retained workflows. An ordinary run could not use them.

After:

An ordinary xmd run under Deno or the compiled binary can use all of those components. The Git checkout containing the contextual working directory becomes the ambient <Repository>, so a root-level <Worktree> creates a worktree from the repository where the document is running.

Node and Bun expose the same components through xmd syntax, keeping the document language consistent across runtimes. Operational use there fails before local or remote state changes because those runtimes do not yet install a repository provider.

Retained workflows keep their existing provider, identity, durability, and behavior.

How it works

xmd run
  → discover the ambient Git repository
  → install the ordinary-run repository provider
  → execute repository, worktree, Git, issue, and pull-request components
  → operate through the selected checkout and configured Git host

A component selects a repository through RepositorySelection, which identifies a target but grants no authority. The installed provider authenticates every selection against private state before accessing a checkout or remote service.

Managed Repository checkouts and Worktrees live under ~/.xmd/repositories and remain after the run ends so work is not lost. A non-blocking advisory lock gives one execution exclusive use of a managed checkout. Another process selecting the same checkout is refused immediately, and process termination releases the lock without deleting the checkout.

A pull request requires evidence that the same execution successfully pushed the exact repository, checkout, branch, destination, and commit. That evidence cannot be supplied by a document or reused by another execution.

Review guide

Start with: packages/workflow/src/composition/selection.ts

Then review:

  1. packages/workflow/src/composition/api.ts — provider contracts and refusing defaults
  2. packages/workflow/src/deno/run-composition/provider.ts — ambient repository discovery and ordinary-run operations
  3. packages/workflow/src/deno/run-composition/leases.ts — exclusive checkout ownership
  4. packages/cli/src/run-repositories.ts and packages/cli/src/deno-repositories.ts — runtime registration and Deno provider installation

Look carefully at:

  • Lease ownership lasts for the provider scope. Completing the acquisition task must not release the lock.
  • The shared runtime registration must not import the Deno adapter because its module graph reaches node:sqlite, which Bun cannot load.
  • A nested <Execution host="run"> must use the contextual working directory of the document that launched it, not the process directory.

What must stay true

  • Every runtime describes the same repository components. ORC1 verifies the declarations under Deno, Node, and Bun.
  • A document cannot forge repository authority. Providers authenticate selections and publication evidence against private state.
  • Pull-request evidence belongs to one execution. ORC19 verifies that it crosses neither parent-to-child nor child-to-parent execution boundaries.
  • Managed checkouts survive success, failure, and cancellation; teardown never deletes work.
  • The retained workflow provider and its durable behavior remain unchanged.

How to verify it

deno task test packages/cli/tests/run-composition-deno.test.ts
deno task build
deno run --allow-all --frozen scripts/smoke-run-composition.ts
  • The ordinary-run tests cover ambient repositories, managed checkouts, Git operations, issues, pull requests, provider refusals, authority isolation, and nested executions.
  • scripts/smoke-run-composition.ts uses two compiled binaries to prove that ambient discovery, managed-checkout persistence, cross-process exclusion, and lock release survive deno compile.
  • ORC19 runs a real xmd run outside a Git process directory to prove that nested runs receive the document working directory and that Push evidence remains execution-local.

Scope

Included

  • Repository, Worktree, Dir, Git.Switch, Git.Add, Git.Commit, Git.Push, IssueTracker, Issue, PullRequest, PullRequest.Reviews, PullRequest.Comments, and PullRequest.Checks under ordinary runs.
  • A live provider for the Deno entrypoint and compiled binary.
  • The current Git checkout as the ambient Repository.
  • Persistent, exclusively leased managed checkouts.
  • The effective Git author and committer identity of the person running the document.

Intentionally unchanged

  • Retained workflow identity, effects, replay, resume, and Workspace behavior.
  • Node and Bun do not perform repository operations in this delivery.
  • Hooks, fsmonitor, signing, and repository-supplied credential helpers remain disabled.
  • Managed checkouts are never removed automatically.
  • Ordinary runs do not gain retained workflow recovery or exactly-once execution.

New abstractions

  • RepositorySelection carries a profile-neutral repository target without carrying authority.
  • The ordinary-run provider implements the existing component contracts using live Git and Git-host operations.
  • Managed-checkout metadata and leases preserve work while preventing concurrent mutation of the same checkout.

New dependencies

  • Package: @executablemd/runtime (workspace:*), added to @executablemd/testing
  • Used for: reading the contextual working directory when a nested execution is handed to its host
  • Why existing dependencies are insufficient: API.Env, which owns the contextual directory, belongs to @executablemd/runtime

Risks and limitations

  • Node and Bun expose the components but refuse their operational use until they have repository providers.
  • A failed or interrupted run can leave a managed checkout behind. This preserves work; cleanup remains an explicit future operation.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

Make the complete repository-composition vocabulary available to an ordinary
`xmd run`, with a live Deno provider and the current Git repository as the
ambient Repository, while the retained workflow implementation keeps its own
provider of the same component contract.

The thirteen components — Repository, Worktree, Dir, the four Git operations,
PullRequest and its three evidence reads, IssueTracker and Issue — become one
shadowable declaration array that `xmd syntax`, `xmd plan`, a workflow
attachment and an ordinary document execution all consume, so one language is
described and resolved everywhere. What a name does is the installed provider's.

Components now observe a profile-neutral `RepositorySelection`: an opaque
provider-minted identifier, a display name, the credential-free repository
identity and the selected checkout path, and no authority at all. Every
operation authenticates the selection it was handed against private provider
state, so a replaced contextual Repository can misname a checkout and be refused
but can never reach one.

The ordinary provider discovers the ambient repository once before root
expansion, keeps managed checkouts under `~/.xmd/repositories` behind version 1
sidecars and execution-owned non-blocking advisory locks, performs local Git
directly with no transaction and no replay, and authorizes `<PullRequest>` from
private Push evidence that crosses no execution. Node and Bun register the same
declarations and install no operational provider.
)

Executes the rest of the frozen ORC1–ORC21 matrix and corrects who an ordinary
commit is by.

An ordinary `<Git.Commit>` now records the invoking user's own effective Git
author and committer identity, captured once from the trusted host's
environment and configuration before a document expands and read back off the
object it wrote. A workflow run keeps its one fixed identity — its retained
state must not depend on whose machine made it — and an ordinary run inverts
that, because the commit lands in that person's checkout. Nothing else is
borrowed: hooks, file-system monitors, signing programs and repository-supplied
credential helpers stay disabled. A host that can name no identity refuses that
one component and names the commands that fix it rather than substituting the
workflow name; every other component stays usable.

Three defects the new evidence found, all fixed:

- a managed-checkout lease was released when the task that took it completed
  rather than when the provider's scope ended, so a second process could take a
  slot an interactive Session was still working in;
- the managed root canonicalized to one path before it existed and another
  afterwards, so the execution that created it and every execution after it
  computed different slots — and therefore never contended; and
- the shared CLI module statically imported the Deno adapter, whose graph
  reaches `node:sqlite`, which stopped `xmd` loading under Bun at all.

A working directory reached through a symbolic link now matches the checkout it
is inside, and `scripts/smoke-run-composition.ts` runs two compiled binaries at
once to prove placement, persistence, cross-process refusal and release.
Evidence for ORC5, ORC8, ORC15 and ORC17, written to discriminate rather than
to confirm.

- ORC15: a diagnostic trace of an execution that really published grants
  nothing. A `<PullRequest>` handed one is refused, so what authorizes a pull
  request is evidence an execution holds rather than a record describing one.
- ORC5: a run with no origin does local work and refuses to publish before
  reaching anything; a run with an origin opens a session and transports; a run
  with a Git host configured reaches it. Three counters that can each fail on
  their own, so no single stub makes the set pass.
- ORC8: a managed Repository survives an authored failure inside its body, and a
  Push result handed back by middleware that never performed one grants nothing.
- ORC17: all three pull-request read collections are read, each from its own
  route.
An `<Execution host="run">` child is a root execution in a scope that does not
descend from the document's, so it inherited no `API.Env` handler and stood in
the *process* directory. A `<Dir>` or `<TempDir>` around the element scoped
every component inside it except the child, and the child's own repository
provider discovered its ambient Git from whatever checkout the process happened
to be launched in.

The harness now reads the contextual directory on the last line still inside
the invocation and carries it on `ChildInvocation`, the private value the
terminal hands the trusted provider. Deliberately not on `HostProfileRequest`:
middleware that could see it could swap it, and the directory a child resolves
its root and its repository in would become composed policy's choice rather
than the document's. The run profile installs it first, ahead of the root, the
provider and the execution, so all three agree with the document that asked.

ORC19 now asks this of a real `xmd run` in a subprocess whose process directory
is a temporary directory that is not a Git checkout, with every repository,
managed root and document fixture-owned and `HOME` redirected. A break in
propagation therefore refuses for want of a repository rather than operating on
the checkout the suite runs from. The fourth case proves that refusal directly,
which is what stops the first from passing for the wrong reason.

Two claims are asked of siblings rather than of a parent and its child, and the
tests say why: a managed checkout stays leased for the whole run of whoever
touched it, so a parent and a child cannot share one; and a run discovers its
ambient repository once, when its provider is installed, from the process
directory — which here is deliberately not a repository. The parent's side of
the isolation is the lease case, where a parent's hold survives its child's
teardown.
The previous commit claimed parent/child Push-evidence isolation could not be
asked in one process. That was wrong, and the claim is removed. Only reselecting
the same *managed* slot conflicts with the parent's lease; caller-owned ambient
Git carries no lease at all, so two executions can use one checkout in sequence.
That makes ambient Git the correct fixture for this criterion, not a barrier to
it.

A separate subprocess now stands in a fixture-owned temporary Git checkout and
asks the boundary both ways, over the same checkout, origin, branch and head:

- the parent performs a real Push, and a `host="run"` child immediately asks for
  a `<PullRequest>` from that same head, and is refused; and
- a child performs the Push, tears down, and the parent asks from the head its
  own child just published, and is refused.

Both refusals are for missing successful Push evidence and both land before any
Git host is reached. The implementation states that itself — "Nothing was
observed at the Git host, and no pull request was created" — so the test asserts
that sentence rather than inferring the ordering. A second, independent reading
corroborates it: the origin here is a local path, so an execution that had got
past the evidence gate would have failed with "no usable origin" instead, and
that sentence is asserted absent.

Standing in a repository keeps the fixture escape-safe on its own terms: a
regression in contextual-directory propagation can reach only the disposable
clone this fixture made. The non-Git-cwd case is kept unchanged and carries the
other half of the argument — that the propagation is real rather than
incidentally agreeing with where the process stands. The contextual-cwd,
sibling-evidence and parent-lease cases are kept as accepted.
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

PR #689: ✨ Give an ordinary xmd run the repository-composition vocabulary (#643)

91 files, +8928 / -768

Scope

🔴 PR has 9696 lines changed. Split into focused PRs.

🟡 9696 lines changed. PRs under 400 receive more thorough review.

🟡 91 files changed. Are all changes related?

🟡 Changes span 11 directories.

🟡 PR mixes config and source changes.

🟡 New abstraction files: packages/workflow/src/deno/run-composition/provider.ts. Verify 3+ consumers.

Structural

🟡 Interface declarations with no consumers: Committed, Switched.
Symbol Declared at Refs in diff Why flagged
Committed packages/workflow/src/deno/composition/commit.ts:119 1 referenced ≤1× within the added diff (pre-existing usages not counted)
Switched packages/workflow/src/deno/composition/switch.ts:79 1 referenced ≤1× within the added diff (pre-existing usages not counted)

🟡 1 console statements.

Oxlint structural signals:

  • no-unused-vars ×9: packages/workflow/src/deno/composition/provider.ts, packages/workflow/tests/support/run-composition.ts, packages/workflow/tests/support/pull-requests.ts (+2)
  • no-empty-function ×2: packages/cli/src/cli.ts, packages/cli/src/run-repositories.ts
  • no-unnecessary-type-assertion ×1: packages/testing/src/execution-harness.ts
  • no-unnecessary-boolean-literal-compare ×1: packages/workflow/tests/support/issue-scenario.ts

Slop

Oxlint slop signals:

  • no-console ×4: packages/cli/src/cli.ts, scripts/smoke-run-composition.ts

Static Analysis

Oxlint: 67 diagnostics across 25 files (14 rules)
Density: 0.008 violations/added-line

no-shadow (24): packages/workflow/src/composition/components/Repository.ts, packages/workflow/src/composition/components/PullRequest.ts, packages/workflow/src/composition/components/GitSwitch.ts (+10)
no-unused-vars (9): packages/workflow/src/deno/composition/provider.ts, packages/workflow/tests/support/run-composition.ts, packages/workflow/tests/support/pull-requests.ts (+2)
no-base-to-string (6): packages/workflow/tests/support/run-composition-child.ts, packages/workflow/tests/support/issue-scenario.ts
unbound-method (5): packages/workflow/tests/support/pull-requests.ts, packages/testing/src/execution-harness.ts, packages/workflow/tests/support/run-composition.ts
no-console (4): packages/cli/src/cli.ts, scripts/smoke-run-composition.ts
consistent-return (4): packages/workflow/src/deno/composition/push.ts, packages/testing/src/execution-harness.ts, packages/cli/src/cli.ts
no-unsafe-type-assertion (4): packages/testing/src/execution-harness.ts, packages/cli/src/deno.ts, packages/workflow/tests/support/run-composition.ts (+1)
no-useless-spread (2): packages/workflow/src/deno/run-composition/provider.ts, packages/workflow/src/issue/effect.ts
no-array-sort (2): packages/workflow/tests/support/run-composition.ts, packages/workflow/tests/support/issue-scenario.ts
no-empty-function (2): packages/cli/src/cli.ts, packages/cli/src/run-repositories.ts
no-floating-promises (2): packages/workflow/src/deno/run-composition/leases.ts, packages/cli/src/cli.ts
no-useless-fallback-in-spread (1): packages/workflow/src/deno/composition/host.ts
no-unnecessary-type-assertion (1): packages/testing/src/execution-harness.ts
no-unnecessary-boolean-literal-compare (1): packages/workflow/tests/support/issue-scenario.ts

Correctness

No extraneous code patterns detected.

@taras taras changed the title ✨ Give an ordinary xmd run the repository-composition vocabulary (#643) Add <Repository>, <Worktree>, <Issue>, and <PullRequest> to xmd run Sep 1, 2026
@taras

taras commented Sep 1, 2026

Copy link
Copy Markdown
Owner Author

Superseded by a reviewable three-PR stack. Closing unmerged; nothing here is abandoned.

Order PR Branch Scope
1 #694 agent/issue-643-composition-seam profile-neutral RepositorySelection seam; retained workflow adapted and unchanged
2 #695 agent/issue-643-run-provider the complete ordinary provider, reachable only from tests
3 #696 agent/issue-643-run-profile root and nested xmd run exposure; carries Closes #643

Merge strictly bottom-up: #694#695#696.

The stack's final tree differs from this PR's head (9b34403f) only by test-file partitioning. Every byte of production, specification and CI content is identical — verified by git diff --name-status, which lists nothing outside *.test.ts, the new shared-fixture module, and scripts/runtime-test-exclusions.ts.

The partitions preserve their inventories exactly: the 1,928-line workflow tier suite became three capability files with 15 describe blocks and 51 cases before and after, and an identical sorted set of every describe and it title; the Deno CLI suite split into root-provider and nested-child files with the nested block carried verbatim.

ORC1–ORC21 pass across the stack, each block observed individually rather than inferred from an aggregate. deno task verify:clean completed all nine steps with exit 0 against #696's head.

This head and its backup refs are left intact.

@taras taras closed this Sep 1, 2026
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.

Add <Repository>, <Worktree>, <Issue>, and <PullRequest> to xmd run

1 participant