@automators/engineering
v0.7.0
Published
Shared engineering contracts, skills, and the local publishing bridge between Codex, Claude Code, or Cursor and Operator Engineering.
Readme
@automators/engineering
Shared engineering contracts, skills, and the local publishing bridge between Codex, Claude Code, or Cursor and Operator Engineering.
Engineering work starts in the developer's local coding agent. Operator is the shared review and evidence surface for artifacts, deployments, previews, sandboxes, and teammate feedback; developers do not need to start a run or create an outcome there first.
The installed harness keeps three parts of user intent separate: the product or subject being changed, the artifact being created, and the publication destination. “Share this on Operator” therefore means finish the artifact for the named product and publish it to Operator. It does not make Operator the product being designed unless the request explicitly says so.
Product UI mockups and prototypes are implemented as runnable, code-native
interfaces in the target repository's frontend stack. The Foundation UI skill
requires the consumer's root DESIGN.md and pinned @automators/foundation
rules, semantic HTML, responsive states, and a primary interaction. Generated
images and screenshots may supplement the preview but cannot replace it.
Install the shared harness
Run this once in each repository and again when the managed harness version changes:
npx @automators/engineering initRun the command from the repository root or pass the repository path. init
is not a global Codex installer, so running it from your home directory will
not configure future projectless sessions. Install the repository's
automators-engineering Codex plugin for that workflow.
For projectless Codex sessions, first ensure the Codex CLI is available (the
official macOS/Linux installer is
curl -fsSL https://chatgpt.com/codex/install.sh | sh), then run:
codex plugin marketplace add automators-com/engineering --ref main
codex plugin add automators-engineering@automatorsRestart Codex after installing the plugin. New sessions can then start with the task directly, without naming the Engineering package or a skill.
For example, the full starting prompt may simply be:
Implement the billing settings redesign, verify it, and share a review package on Operator.
The harness selects planning, implementation, verification, Foundation, and publishing procedures from that intent. When a material product choice remains, the agent uses the coding client's native structured question UI when available: two to four mutually exclusive options, the evidence-supported recommendation first, one sentence about each consequence, and a free-form response. It does not ask the developer to select a skill, artifact format, or upload strategy.
The idempotent command preserves repository-owned instructions and installs the same discoverable Automators skills/rules for Codex, Claude Code, and Cursor. It never creates a repository credential file.
Map ambiguous work before implementation
Do not ask developers to select a skill. Requests such as “Map this before we
implement it” and “Continue this map: <url>” are enough. For qualifying work,
the agent proposes an observable goal, a default canonical GitHub host, and the
first material questions, then asks for one confirmation before any GitHub
write. Small or already-understood work stays in the normal planning and
implementation flow.
The CLI exposes a small helper surface under
npx @automators/engineering wayfind:
Install GitHub CLI (gh) on PATH, authenticate it to github.com, and use a
release with native sub-issue flags. doctor checks those prerequisites.
# Read-only unless --setup is added after the user approves GitHub writes.
npx @automators/engineering wayfind doctor \
--repositories owner/product,owner/platform [--setup] --json
npx @automators/engineering wayfind claim \
--issue <url|number> --worker <id> --scope <text> [--minutes 60] \
[--supersede-comments <id,id>] --json
npx @automators/engineering wayfind renew \
--issue <url|number> --claim <token> [--minutes 60] --json
npx @automators/engineering wayfind wait \
--issue <url|number> --claim <token> --human <login> \
--request-file <path|-> --json
npx @automators/engineering wayfind resume \
--issue <url|number> --claim <token> --worker <id> \
[--response-comment <id>] [--minutes 60] --json
npx @automators/engineering wayfind release \
--issue <url|number> --claim <token> --json
npx @automators/engineering wayfind status \
--map <url|number> [--publish] --json
npx @automators/engineering wayfind handoff \
--map <url|number> --file <manifest.json|-> --json
npx @automators/engineering wayfind validate-handoff \
--handoff <url|number> --jsonEvery bare issue number requires common --repository owner/repo; a full issue
URL does not. Use --json for automation. Exit code 0 is complete success, 2
is a valid non-ready or partial envelope on stdout (doctor.ready: false,
resume.resumed: false, release.readyToClose: false, or
handoff.readyForFinalization: false), and 1 is a failure. doctor, status
without --publish,
and validation performed by the other helpers are read-only. --setup, claim
events, wait/resume/release events, published status, and handoff records are
GitHub writes and run only within the user's approved Wayfinding operation.
claim posts a structured claim and reads it back so only the winner proceeds;
after it succeeds, begin work directly. renew --minutes N requests an expiry
N minutes from now and never accumulates duration onto the old expiry; an early
request that would not extend the lease returns extended: false without a
write. wait
pauses active work in a durable human-wait state on the same token and returns
the dedicated request comment's request.id and request.url; and release
ends ownership explicitly. Before claim, renew, wait, or resume starts or
continues work, the helper rediscovers the decision's native parent and
authenticates the map, decision, relationship transitions, issue lifecycle, and
direct blockers. Reserve resume for a later worker context, an
explicitly selected human reply, or expired recovery. A human-wait resume must
include --response-comment <id> for the exact GitHub reply comment; on success its
acceptedResponse contains that comment's id, url, author, and body.
Later-context resumes verify or repair that sealed response automatically and
do not require the comment ID again. If ownership has since moved, response
repair can return resumed: false with the reason without taking ownership.
That exit-2 result is still a valid JSON envelope: persist its
acceptedResponse, follow the reason, and use an identical retry to retrieve
the same sealed response rather than treating it as command failure.
Resuming active work or an accepted human response retains the current token.
Recovering an expired claim atomically creates and returns a new claimToken;
replace the stored expired token with that value before the next renew, wait,
resume, or release. status --json exposes every token and its resume
disposition for an intentional later-context resume, without raw comment parsing.
Malformed, foreign-edited, or otherwise unauthenticated coordination from a
current repository writer is classified as needs-reconciliation and is
called out in both Markdown and JSON before anyone attempts a claim. Status
preview and publication authenticate the same planning state before advertising
work as ready. A closed decision with an open blocker, no Resolution, or missing
durable accepted-human proof is needs-reconciliation, not recently decided.
A marker from an unaffiliated nonwriter is advisory and cannot claim or veto work.
During a visible access gap, an issue-bound claim from a historically associated
author is conservatively quarantined. When complete original-author history is
available, quarantine preserves the strongest validated state ever seen: any
durable wait wins, and bounded leases retain their latest availableAfter.
Redacted, capped, removed-marker, or standalone transition history that cannot
be proved remains fail-closed and can require replacing and relinking the
dedicated decision. This means a historically associated read-only account can
cause an availability loss, including a durable-looking wait; GitHub does not
provide the historical permission proof needed to distinguish that from safe
offboarding. A marker proven by complete edit history to have first appeared in
a later second after decision closure is advisory. GitHub author association is
an uncertainty signal, never write authority.
Current permission at read time is the authorization boundary. If access is restored, GitHub supplies no permission-history proof, so the helper accepts an intact current record again; restoration is an administrator assertion, not cryptographic evidence that the gap was safe. Recovery can instead wait for a finite safety boundary, replace and relink, or let a repository admin supersede only exact live-looking quarantined comment IDs that status marks eligible. That replacement binds comment/node/author/body identity, rechecks access around the write, and remains authoritative if the former account later regains access. Never guess IDs or use supersession against a current writer. At handoff, the map and decision authors, every retained body or title editor, and the latest effective close or reopen actor must also be current repository writers. Title and lifecycle history are attested from GitHub's native timelines. A triage-authored reopen is repaired with a writer-authored close/reopen sequence.
The latest effective add or remove for native parent membership and each direct
blocked-by edge must be by a current writer in the repository that owns the
relationship. A decision is eligible only with exactly one active canonical
map parent. A writer repairs a relationship by removing and re-adding it to the
intended state. Redacted or incomplete history fails closed. A resolved direct
blocker must have been finally closed by a current writer in the blocker's own
repository, including cross-repository dependencies; a later relationship
transition invalidates that sealed close. The planning digest seals the
blocker's canonical closedAt.
This current-authority model deliberately trades availability for a planning graph collaborators can trust. Restoring access is an administrator assertion, not proof about the gap; replace the decision or repair its native relationships under a current writer when that distinction matters.
Use worker IDs such as
<client>:<map-number>:<session-id> and do not mutate one token concurrently.
Lease output includes the short clock-skew safety window as availableAfter.
Planning invalidation does not prevent release cleanup. It can record cleanup
and return exit 2 with readyToClose: false and
closeBlockedReason, without safeToCloseAfter; repair the graph and replay
the identical release. Only readyToClose: true authorizes using the returned
safeToCloseAfter. Read GitHub's authoritative Date header and close the
exact full decision URL only at or after that value; closing in the release
edit's GitHub second deliberately fails chronology.
handoff validates and creates the native handoff child and closes the map;
validate-handoff --json returns the sealed manifest and is the implementation
gate.
All mutating commands recheck the authenticated viewer's repository write access around canonical changes. Trusted claims, durable human-response proofs, shared status edits, and handoff authors also require current write access. A durable human wait never expires and only the exact account that owns its canonical comment can resume or release it. If that account is unavailable, replace and relink the dedicated decision issue.
Generated status publication maintains one active managed dashboard, normally editing it in place. Near GitHub's retained edit-history limit, the helper rotates to a fresh dashboard and turns older managed dashboards into bound neutralization records. Retired tombstones remain auditable and must not be deleted.
Once a released decision has a non-empty ## Resolution, status marks it as
finalization pending and new claims or resumes cannot restart it before safe
closure. Clear Resolution only to intentionally reopen the decision for work.
Closed decision records are intentionally strict. A body/protocol/title, lifecycle, native relationship, or comment deletion transition in or after the close second requires reopen, repair, a wait into a later GitHub second, and reclose; GitHub deletion events do not expose the deleted body, so replace and relink the dedicated decision when the record cannot be restored. Deleted map dashboards are non-authoritative and republishable; they produce a map note rather than invalidating a sealed handoff. The final handoff boundary is the next GitHub second after every sealed map body/title edit, decision close, native relationship transition, and external blocker close.
Before closure, cleanup by a currently unauthorized account is advisory so a
public outsider cannot veto work. GitHub therefore cannot distinguish a
revoked writer deleting their own canonical record from harmless outsider
cleanup; that deletion can erase ownership before availableAfter. Offboard by
releasing or replacing/relinking the decision before removing access. If
external evidence shows such a deletion, replace and relink the decision.
The handoff file is a pre-seal manifest; callers omit protocol, version, and
planningDigest because the helper verifies and injects them:
{
"generatedAt": "2026-08-20T10:15:30.000Z",
"map": {
"title": "[Wayfinding] Goal",
"url": "https://github.com/owner/map/issues/1"
},
"repositories": [
{ "repository": "owner/repo", "ref": "40-character-lowercase-commit-sha" }
],
"acceptedDecisions": [
{
"name": "[Decision] Choice",
"url": "https://github.com/owner/repo/issues/2",
"decision": "Exact ## Resolution text",
"decidedAt": "2026-08-20T10:00:00.000Z"
}
],
"scope": ["Implementation outcome"],
"exclusions": [],
"constraints": [],
"doneChecks": ["Observable completion check"],
"evidence": [],
"reconciliationBlockers": []
}For every acceptedDecisions[] entry, decidedAt must exactly equal the
decision issue's canonical GitHub closedAt timestamp; a local clock or comment
timestamp is not interchangeable.
The map is a GitHub issue, and decisions are attached with GitHub native sub-issues. Use native blocked-by relationships for ordering rather than copying a dependency graph into Operator. The one active generated status dashboard is normally updated in place, rotates near the retained-history limit, and groups human-readable decisions under Ready now, In progress, Waiting for you, Blocked, and Recently decided. The map body uses exactly the ordered Goal, Done when, Decisions made, Open questions, Out of scope, and Risks sections, with a non-empty Goal and Done when.
Use these stable public conventions:
| Record | Title | Labels |
| ---------------------- | ----------------------- | ---------------------------------- |
| Map | [Wayfinding] <goal> | wayfinding, wayfinding-map |
| Agent decision | [Decision] <question> | wayfinding, agent-work |
| Human decision | [Decision] <question> | wayfinding, needs-human-choice |
| Implementation handoff | [Handoff] <goal> | wayfinding, wayfinding-handoff |
Every decision also contains exactly one body marker matching its mode label.
Use this structure for agent work; substitute needs-human-choice in both the
marker and label for a human decision. Leave Resolution blank until settled.
<!-- automators-wayfinding-decision-mode:v1 agent-work -->
## Question
...
## Why it matters
...
## Acceptable evidence
...
## ResolutionChart a decision with gh issue create, using native --blocked-by arguments
for its dependencies, then attach it to the map with
gh issue edit MAP --add-sub-issue. Do not infer readiness from duplicated text
links when native GitHub relationship state is available. A decision can start
or continue only while that exact native parent remains its one active canonical
map.
For work spanning repositories, host the map in the repository that owns the cross-cutting outcome. Put each decision ticket in the repository whose maintainers own the resulting decision and attach it as a native child by full URL. Dependencies remain native across repositories; preflight stops instead of creating a text-link fallback graph.
| Surface | Owns | | ------------------------------- | -------------------------------------------------------------------- | | GitHub | Wayfinding workflow state and the canonical planning decision record | | Operator | Immutable exact-revision evidence and review events | | Merged repository docs and code | Durable product truth |
Operator is therefore not a second tracker. A decision ticket may link to an immutable Operator revision for a prototype, research package, test result, or review event, but the authorized decision is recorded in GitHub and reconciled into merged repository documentation or code.
At completion, the helper validates and creates a parent-linked [Handoff]
<goal> issue, then closes the map. Planning records that can merge without
production code are reconciled first; product code and documentation changes
remain explicit implementation scope. automators-implement runs
validate-handoff --json in a fresh context and consumes its verified manifest;
it does not reinterpret map rows as build slices. Each repository entry must be
an immutable 40-character commit SHA. Each closed decision must have exactly
one ## Resolution section matching the manifest. Before a
needs-human-choice decision closes, a successful resume seals durable
provenance for the exact accepted human response, and handoff validation requires
that record. Operator evidence URLs must use the configured trusted Operator
HTTPS origin (default https://operator.automators.com) and the exact
/revisions/<id> path. The runtime validates that origin and path, not the
remote existence of the revision. The helper injects a digest of the current map
body and native decision graph so callers do not reproduce hashing logic.
Pass request and handoff input as - to read stdin and avoid repository-local
shadow files. If a file is necessary, use a restrictive temporary file outside
the repository and remove it after the command. These values are published at
repository issue visibility, so neither form may contain secrets. If an open
map body was edited in GitHub's current second, handoff --json exits 2 with
readyForFinalization: false and safeToFinalizeAfter. Without a returned
handoff URL, no child was created; wait for the authoritative GitHub Date
boundary and retry the identical manifest. With a returned handoff URL, the
map changed during creation and was deliberately left open; unlink and close
that stale child, refresh the manifest, wait for the boundary, and retry.
If GitHub is unavailable, access is read-only, or a required capability cannot be used, the helper preflights that boundary before writing and fails closed. Once a multi-write operation has begun, an interruption can leave explicit durable records; rerun the helper or reconcile those records manually rather than assuming atomic rollback. The agent returns the proposed goal, host, and questions plus the exact authorization or manual GitHub action needed. It never substitutes Operator or a local file as a parallel tracker.
Authenticate local publishing
Create a user-scoped token under Operator Account → MCP tokens, then expose
it to the local agent process as OPERATOR_ENGINEERING_TOKEN. Tokens inherit
the owner's current permissions rather than carrying separate scopes; the
complete loop needs mcp:use, engineering:read, and engineering:write. Use
your shell's secure environment integration or a password manager; do not put
the token in a repository .env, agent instruction, artifact, command argument,
or committed configuration file.
For a non-production Operator instance, set its origin separately:
export OPERATOR_ENGINEERING_URL=https://operator.example.comThe production origin defaults to https://operator.automators.com.
Publish shared context
The CLI infers repository, branch, and commit from Git. Operator resolves an existing outcome or creates the shared work record from that provenance, so an Operator-originated outcome or run is not required.
npx @automators/engineering publish artifact \
--kind plan \
--title "Billing migration plan" \
--file docs/billing-migration.md \
--status proposedWhen one human judgment needs a primary artifact and supporting evidence, publish an immutable review-package revision:
{
"key": "billing-settings-review",
"title": "Billing settings redesign",
"reviewRequest": "Approve the interaction and copy, or request concrete changes.",
"items": [
{
"role": "primary",
"kind": "prototype",
"title": "Interactive billing settings",
"file": "artifacts/billing-settings.html"
},
{
"role": "supporting",
"kind": "implementation-summary",
"title": "Verification notes",
"file": "artifacts/verification.md"
},
{
"role": "supporting",
"kind": "visual-evidence",
"title": "Mobile state",
"file": "artifacts/billing-mobile.png"
}
]
}npx @automators/engineering publish package \
--file artifacts/review-package.jsonEach item has role, kind, title, and exactly one of content or file.
Exactly one item is primary; the rest are supporting. Optional fields are
format, mimeType, fileName, summary, status, and metadata.
HTML, Markdown, JSON, CSV, SVG, and other UTF-8 text remain inline. PDF, PNG, JPEG, WebP, and GIF files use a short-lived direct PUT to private storage. The Operator bearer token is sent only to Operator; it is never sent to the signed Blob URL. Files must stay inside the selected repository, each private file is limited to 25 MB, a package is limited to 50 items and 100 MB total, and one publication can reserve at most 20 private files.
An all-inline package is published atomically. For a new mixed package, the
command first creates the Operator workstream from the inline items, then
uploads and claims the private items, and finally assembles the package in the
manifest's original order. A new package containing only PDF/image files needs
--outcome-id; include a small inline summary when the workstream should be
created automatically. If a mixed publication is interrupted after its first
write, rerun only after inspecting the returned Operator outcome: completed
artifact revisions are immutable and the retry can add a new revision while
expired upload reservations are cleaned safely.
Success returns the exact authenticated team URL:
https://operator.automators.com/engineering/review-packages/<package-id>/revisions/<number>Use --json for a typed receipt. It contains package and artifact identifiers,
hashes, outcome provenance, and the review URL, but never reservation secrets or
signed upload URLs.
Register a testable environment independently from a document artifact:
npx @automators/engineering publish preview \
--provider vercel \
--deployment-id dpl_123 \
--url https://billing-preview.example.com \
--status readyThe same command supports deployment and sandbox. Environment states are
queued, building, ready, failed, cancelled, or inactive; a ready
environment requires an HTTPS URL. Artifact kinds remain open-ended and their
agent-authored statuses remain limited to draft, proposed, informational,
or unverified. Human approval states remain owned by Operator.
Use --outcome-id to target a known outcome, or --outcome-title and
--outcome-description to supply a human-friendly title for newly resolved
work. Use --repository, --branch, --commit, and --pr only when Git cannot
infer the correct provenance.
The CLI generates a stable idempotency key from provenance and content. An
explicit --idempotency-key is available for CI and provider webhook adapters.
Retrieve feedback
npx @automators/engineering feedbackThis returns unresolved artifact and review-package comments plus explicit
package approvals or change requests matching the current repository context.
Human approval remains evidence: it does not bypass GitHub protection, a
Wayfinding handoff, or the normal merge boundary. Add --json for an agent- or
script-readable response; the human view includes the exact package revision
link for review decisions.
Typed client
import {
createOperatorEngineeringClient,
createOperatorEngineeringIdempotencyKey,
} from "@automators/engineering/operator";
import { publishOperatorReviewPackage } from "@automators/engineering/operator-review-package";
const client = createOperatorEngineeringClient();
const input = {
source: {
repositoryFullName: "automators-com/operator",
branch: "feature/shared-artifacts",
commitSha: "0123456789abcdef0123456789abcdef01234567",
},
items: [
{
type: "artifact" as const,
kind: "implementation-summary",
title: "Shared artifacts",
summary: "Local publishing bridge and Operator review surface.",
status: "informational" as const,
metadata: {},
},
],
};
const result = await client.publish({
...input,
idempotencyKey: createOperatorEngineeringIdempotencyKey(input),
});The client validates requests and responses, sends the user token only as an
HTTPS bearer credential, times out requests, and never stores credentials.
publishOperatorReviewPackage is the higher-level API that reads a manifest,
keeps UTF-8 artifacts inline, performs verified private direct uploads, and
creates the exact immutable package revision. Lower-level reservation,
completion, cleanup, and standalone package methods remain available on the
typed client for adapters that need them.
Contracts and safety gates
The package continues to provide canonical data contracts, short-lived lease signing and verification, resource ceilings, and high-risk path classification for hosted control-plane consumers:
import {
RunRequestSchema,
assertUnattendedLimits,
} from "@automators/engineering";Explicit subpaths are available for narrower imports:
import { RunRequestSchema } from "@automators/engineering/contracts";
import { assertUnattendedLimits } from "@automators/engineering/gates";Hosted Eve compatibility
The existing hosted Eve publish_artifact tool remains compatible with the
signed Operator event callback. It keeps long-lived Operator and GitHub
credentials outside its sandbox. Local publishing uses the separate
user-authenticated ingestion endpoint and does not require an Eve session,
task, run, or outcome version.
Rollout order
Deploy the Operator ingestion and feedback endpoints first and smoke-test their
401, 403, publish, and feedback behavior. Only then merge or publish
@automators/[email protected]; merging the Engineering repository's main
branch triggers its package-release workflow. After publication, rerun
npx @automators/engineering init in each repository to install harness v9.
