Story
As a Plugin or trusted-host author, I want @executablemd/git/api names to describe the Git and Repository operations they provide, so I can call or replace a contextual API without translating package-internal layer names or Git CLI implementation terms.
Example
The public surface reads in the same vocabulary as the components and values it supports:
import { Git, GitQuery, Repository } from "@executablemd/git/api";
const selected = yield* Repository.operations.select(request);
const committed = yield* Git.operations.commit(invocation);
const root = yield* GitQuery.operations.root();
Git.operations.commit(...) is the provider operation behind <Git.Commit>. GitQuery separately answers read-only questions about the repository containing the contextual working directory.
Current gap
#834 established /api as the sole public route to Git's contextual APIs, but those APIs retain names from their former implementation layers:
RepositoryComposition.operations.selectRepository(...)
RepositoryComposition.operations.selectWorktree(...)
RepositoryComposition.operations.repository()
GitComposition.operations.switchBranch(...)
GitComposition.operations.addPaths(...)
GitComposition.operations.commitIndex(...)
GitComposition.operations.pushCurrentBranch(...)
Git.operations.revParse(...)
Git.operations.repositoryRoot()
Git.operations.objectFormat()
Git.operations.readObject(...)
Composition describes an internal layer rather than the answer a consumer receives. The two Git APIs also compete for the name Git: the read-only query capability has it, while the durable operations corresponding to <Git.*> components are called GitComposition.
Their contextual identity strings still name their former workflow owner and, in two cases, the composition layer. These identities were published by @executablemd/workflow@0.12.1; changing them is therefore an intentional compatibility break, not a mechanical rename.
Public contract
Repository selection
export interface RepositoryApi {
select(request: RepositoryRequest): Operation<RepositorySelection>;
worktree(
repository: RepositorySelection,
request: WorktreeRequest,
): Operation<RepositorySelection>;
ambient(): Operation<RepositorySelection | undefined>;
}
export const Repository = createApi<RepositoryApi>(
"executablemd.git.repository",
// existing provider behavior
);
select answers the authored <Repository>, worktree answers its named linked checkout, and ambient asks for the host-provided Repository used outside a lexical <Repository>.
The lexical Repository API keeps its public names and receives its new identity:
RepositoryContext.operations.current
currentRepository()
// identity: executablemd.git.repository.current
Durable Git operations
export interface GitApi {
switch(invocation: GitSwitchInvocation): Operation<GitSwitchResult>;
add(invocation: GitAddInvocation): Operation<GitAddResult>;
commit(invocation: GitCommitInvocation): Operation<GitCommitResult>;
push(invocation: GitPushInvocation): Operation<GitPushOutcome>;
}
export const Git = createApi<GitApi>(
"executablemd.git",
// existing provider behavior
);
The operations correspond directly to <Git.Switch>, <Git.Add>, <Git.Commit>, and <Git.Push>.
Read-only Git queries
export interface GitQueryApi {
resolve(revision: string): Operation<string>;
root(): Operation<string>;
format(): Operation<GitObjectFormat>;
read(commit: string, path: string): Operation<string>;
}
export const GitQuery = createApi<GitQueryApi>(
"executablemd.git.query",
// existing working implementation
);
The direct operation aliases are:
resolveGitRevision
gitRoot
gitObjectFormat
readGitObject
GitQuery stays separate from Git. Its operations work by default and only inspect the contextual checkout; Git performs authored transitions through an installed repository provider and refuses when none is installed.
Neighboring API identities
The remaining contextual APIs keep their TypeScript names and operations while moving from the former Workflow namespace to their Git-package identities:
| API |
Identity |
PullRequestAPI |
executablemd.git.pull-request |
IssueApi |
executablemd.git.issue |
IssueTrackerContext |
executablemd.git.issue-tracker.current |
GitHost |
executablemd.git.host |
Compatibility boundary
The old TypeScript names, operation names, and contextual identity strings receive no aliases, dual handlers, or compatibility bridge. A provider built against the released @executablemd/workflow@0.12.1 identities no longer intercepts these APIs. This break is explicit and must be visible in regression evidence rather than hidden behind a fallback.
This source and contextual-identity break does not change executable-document syntax or durable behavior. Existing component names, forms, invocation and result records, normalized failures, effect identities, journal bytes, database rows, and completed replay behavior remain unchanged.
Acceptance
@executablemd/git/api publishes Repository, RepositoryApi, Git, GitApi, GitQuery, and GitQueryApi with exactly the operations and direct aliases above.
- The old
RepositoryComposition, RepositoryCompositionApi, GitComposition, GitCompositionApi, revParse, and repositoryRoot exports and their old operation names are absent.
- Each contextual API uses its exact accepted
executablemd.git* identity; none uses an executablemd.workflow* identity or contains .composition..
- Separately loaded copies using the new identities compose in both directions. A negative control using an old identity does not intercept a new operation.
- A consumer can replace
Repository, Git, or GitQuery and observe ordinary-run and workflow calls reaching that replacement. Renaming only the exports while leaving a host provider on an old identity fails this evidence.
- A document using
<Repository>, <Worktree>, and all four <Git.*> components succeeds in an ordinary run and a workflow with the same normalized results and durable records as before.
- Replaying completed Git effects performs no Git operation.
- In a checkout,
GitQuery resolves a revision, reports the root and object format, and reads a committed path. A lexical replacement can answer all four without invoking Git. The default provider retains the existing refusal outside a checkout.
- Deno, Node, and Bun consumers resolve the new API values and types through
@executablemd/git/api. The emitted npm package has the same names and identities, and a compiled XMD run executes the unchanged component vocabulary.
architecture.md and the Git package/API documentation state the accepted names, ownership, identity break, and separation between durable Git operations and read-only Git queries.
Evidence
Extend the portable packages/git/tests/api-entrypoint.test.ts contract and run it under Deno, Node, and Bun. Its positive path imports every new value and interface through the package export map; its negative path proves the old names are absent from both source and emitted npm surfaces.
Exercise physical loaded-copy composition under every new identity and an old-identity negative control. Run the existing Repository/Git ordinary-run, workflow durability, replay, package-partition, npm-package, and compiled-XMD integration targets that cross these renamed boundaries. deno task check must cover the complete call-site migration, including packages/git/src/deno/composition/provider.ts, whose contents may be skipped by text tools that treat it as binary.
Dependency
#834 delivered the /api boundary and is merged. This Story begins from that delivered surface.
Out of scope
- Changing executable component names or forms.
- Merging
Git and GitQuery into one API.
- Changing invocation types, normalized results, failures, durable effect identities, records, journals, database formats, or replay semantics.
- Adding another Git host, GitHub package, or Plugin.
- Renaming unrelated internal helpers merely because they still describe an implementation layer.
Story
As a Plugin or trusted-host author, I want
@executablemd/git/apinames to describe the Git and Repository operations they provide, so I can call or replace a contextual API without translating package-internal layer names or Git CLI implementation terms.Example
The public surface reads in the same vocabulary as the components and values it supports:
Git.operations.commit(...)is the provider operation behind<Git.Commit>.GitQueryseparately answers read-only questions about the repository containing the contextual working directory.Current gap
#834 established
/apias the sole public route to Git's contextual APIs, but those APIs retain names from their former implementation layers:Compositiondescribes an internal layer rather than the answer a consumer receives. The two Git APIs also compete for the nameGit: the read-only query capability has it, while the durable operations corresponding to<Git.*>components are calledGitComposition.Their contextual identity strings still name their former
workflowowner and, in two cases, thecompositionlayer. These identities were published by@executablemd/workflow@0.12.1; changing them is therefore an intentional compatibility break, not a mechanical rename.Public contract
Repository selection
selectanswers the authored<Repository>,worktreeanswers its named linked checkout, andambientasks for the host-provided Repository used outside a lexical<Repository>.The lexical Repository API keeps its public names and receives its new identity:
Durable Git operations
The operations correspond directly to
<Git.Switch>,<Git.Add>,<Git.Commit>, and<Git.Push>.Read-only Git queries
The direct operation aliases are:
GitQuerystays separate fromGit. Its operations work by default and only inspect the contextual checkout;Gitperforms authored transitions through an installed repository provider and refuses when none is installed.Neighboring API identities
The remaining contextual APIs keep their TypeScript names and operations while moving from the former Workflow namespace to their Git-package identities:
PullRequestAPIexecutablemd.git.pull-requestIssueApiexecutablemd.git.issueIssueTrackerContextexecutablemd.git.issue-tracker.currentGitHostexecutablemd.git.hostCompatibility boundary
The old TypeScript names, operation names, and contextual identity strings receive no aliases, dual handlers, or compatibility bridge. A provider built against the released
@executablemd/workflow@0.12.1identities no longer intercepts these APIs. This break is explicit and must be visible in regression evidence rather than hidden behind a fallback.This source and contextual-identity break does not change executable-document syntax or durable behavior. Existing component names, forms, invocation and result records, normalized failures, effect identities, journal bytes, database rows, and completed replay behavior remain unchanged.
Acceptance
@executablemd/git/apipublishesRepository,RepositoryApi,Git,GitApi,GitQuery, andGitQueryApiwith exactly the operations and direct aliases above.RepositoryComposition,RepositoryCompositionApi,GitComposition,GitCompositionApi,revParse, andrepositoryRootexports and their old operation names are absent.executablemd.git*identity; none uses anexecutablemd.workflow*identity or contains.composition..Repository,Git, orGitQueryand observe ordinary-run and workflow calls reaching that replacement. Renaming only the exports while leaving a host provider on an old identity fails this evidence.<Repository>,<Worktree>, and all four<Git.*>components succeeds in an ordinary run and a workflow with the same normalized results and durable records as before.GitQueryresolves a revision, reports the root and object format, and reads a committed path. A lexical replacement can answer all four without invoking Git. The default provider retains the existing refusal outside a checkout.@executablemd/git/api. The emitted npm package has the same names and identities, and a compiled XMD run executes the unchanged component vocabulary.architecture.mdand the Git package/API documentation state the accepted names, ownership, identity break, and separation between durable Git operations and read-only Git queries.Evidence
Extend the portable
packages/git/tests/api-entrypoint.test.tscontract and run it under Deno, Node, and Bun. Its positive path imports every new value and interface through the package export map; its negative path proves the old names are absent from both source and emitted npm surfaces.Exercise physical loaded-copy composition under every new identity and an old-identity negative control. Run the existing Repository/Git ordinary-run, workflow durability, replay, package-partition, npm-package, and compiled-XMD integration targets that cross these renamed boundaries.
deno task checkmust cover the complete call-site migration, includingpackages/git/src/deno/composition/provider.ts, whose contents may be skipped by text tools that treat it as binary.Dependency
#834 delivered the
/apiboundary and is merged. This Story begins from that delivered surface.Out of scope
GitandGitQueryinto one API.