This text was generated by an LLM (how cgwalters uses LLMs). cgwalters has not reviewed it yet.
jmarrero-forge's copy of cgwalters-forge/actions: its GitHub Actions, one per directory, with the two agentic-job wrappers renamed and retargeted to jmarrero-forge's deployment. Our own changes are kept to that configuration, so that the copy can follow upstream (Syncing with upstream). The text below is upstream's, but for what this copy changes; where it describes cgwalters-forge's organization (its rulesets and onboarding), that is upstream's process, not ours yet. Our work items are in jmarrero-forge/tracker.
| Action | Status | Roadmap |
|---|---|---|
| lint | actionlint, zizmor and the runner-label policy; this repository's CI calls it | Called from each forge repository's CI |
| workflows-check | Required workflow over a pull request's workflow files: job shape, new dangerous triggers, new zizmor ignores, linter configuration and .gitignore changes, checker references; CI runs its tests with fixture workflows |
An organization ruleset requires it, evaluate mode first |
| secure-host | Runs agentic-job's attested, digest-pinned image: no later step has root or the metadata service, world-write by owner only; CI runs the two-job example, the inputs and the world-write policy on ubuntu-26.04 | agentic-job's own action forwards here; opt-in egress (agentic-job#995) |
| app-token | Mints and masks one role's GitHub App installation token, scoped to named repositories; remint.mjs mints again near expiry or after a 401; CI runs its unit tests, no real mint (no app here) |
Move each role to its app (tracker#766) |
| admit | Fails unless the calling repository's owner id is in its owners.json; both reusable wrappers run it first; CI runs its unit tests | Brokers and tailnet federation match the same ids |
| tailscale | Settings by organization; CI runs its unit tests and checks the socket and CLI are closed after a join that fails, no real join (no tailnet credentials here) | Replace devspace.yml's and agent.yml's tailscale/github-action steps |
One reusable workflow is here too:
jmarrero-agentic-job, an
agent run of cgwalters-forge/agentic-job with this deployment's tailnet
join, inference proxy, runner, agent and model. Our callers pin it by
commit, the one jmarrero's inference broker admits (jmarrero/atomic-setup,
bot/praxis-broker), so a change here reaches runs only once both move.
Any public repository can call it too, and its run's identity
tokens carry the same job_workflow_ref, so the inference broker and the
tailnet federation must match repository_owner_id against the ids in
admit/owners.json as well as that job_workflow_ref;
both wrappers refuse any other owner before the agent job's runner, which
the caller picks, is given the job (admit). It writes
no broker address: a real agent needs the calling repository's variable
INFERENCE_URL, our broker, whose audience jmarrero-praxis-broker is
the default. With an inference-url other than that variable's it needs
an inference-audience too, so that our broker's audience is not sent
elsewhere by default (the review wrapper's variables still default
apart). The agent is claude unless AGENT or the input says otherwise,
with the agent's own model unless AGENT_MODEL names one. It refuses runs
from a private repository, so agentic-job's opt-in for private
repositories, which admits only the calling repository, stays off.
A repository gets agent runs with the workflow below, a bounds file at
.github/agentic-job/dispatch.toml (and fix.toml for the fix kind), a
runner configuration at .github/agentic-job/hosted.toml, and an
environment that gates the apply token; jmarrero-forge/tracker has all four
to copy. The file's header says what else a caller may set.
Both wrappers pin agentic-job v0.6.2, by its commit, and check inference
reachability after the tailnet join, before securing the host. They still compose that tag's
secure-host/internal action, which runs sandbox setup on the host, not
this repository's secure-host image action that the
tag's public secure-host now forwards to, so its egress
proxy stays a host unit. Since v0.6.0 the agent's home no longer copies the
runner image's /etc/skel, toolchains and dotfiles included. The pinned run action publishes
the session endpoint itself; no extra endpoint step is needed here.
Mid-run steering stays off unless the caller's runner configuration enables
[session] watch-item = true. Policy derives the watched item from the
dispatch wrapper's issue (in output-repo) or the review event;
run needs no additional input. Upstream bounds delivery to 10 updates of
8000 characters, quoted as untrusted item text, not instructions.
name: dispatch
run-name: ${{ inputs.kind }} ${{ inputs.repo }}#${{ inputs.item }}
on:
workflow_dispatch:
inputs:
task: {type: string, required: true}
repo: {type: string, required: true}
item: {type: string, required: true}
kind: {type: choice, required: true, options: [implement, triage, research, review, fix]}
permissions: {}
concurrency:
group: dispatch-${{ inputs.kind }}-${{ inputs.repo }}-${{ inputs.item }}
jobs:
run:
# The commit the broker's run-token policy admits.
uses: jmarrero-forge/actions/.github/workflows/jmarrero-agentic-job.yml@COMMIT
permissions: {contents: read, issues: write, pull-requests: write, actions: read, id-token: write}
with:
task: ${{ inputs.task }}
repo: ${{ inputs.repo }}
item: ${{ inputs.item }}
kind: ${{ inputs.kind }}
apply-environment: agent-apply
secrets:
SAFE_OUTPUTS_PAT: ${{ secrets.SAFE_OUTPUTS_PAT }}jmarrero-review is the reusable
event-review wrapper. It composes agentic-job v0.6.2's policy, check,
apply and review helpers, so that the tailnet and the inference broker admit
this file's job_workflow_ref; agentic-job's review workflow can now run a
caller's own network step instead (its #705), which callers have not moved
to. It refuses private repositories, as the dispatch wrapper does. It adds
our tailnet join and defaults: claude, the
agent's own model, ubuntu-26.04, and our broker's audience; the
inference URL is the variable INFERENCE_URL alone. AGENT_MODEL is
shared with dispatched runs, so set it only for a model the reviewing
agent serves too. It has no inputs. Repository/organization variables
AGENT_REVIEW (the reviewing agent, apart from AGENT so that turning
on dispatched runs leaves reviews alone), AGENT_MODEL, AGENT_RUNNER (JSON), INFERENCE_URL,
INFERENCE_AUDIENCE, AGENT_CONFIG, AGENT_CONFIG_REPO and
AGENT_CONFIG_PATH select owner-controlled configuration. Set the last
two for agents needing external configuration; there is no hard-coded
configuration repository. AGENT_CONFIG otherwise uses the pinned
agentic-job hosted configuration. AGENTIC_JOB_TAILSCALE_OAUTH_CLIENT_ID
and AGENTIC_JOB_TAILSCALE_TAGS, read by both wrappers, are the tailnet
login of an organization that tailnets.json
doesn't list; set, they replace a listed organization's entry too. Either
way the wrappers run only for an owner that
admit/owners.json lists.
Call it from the same pull_request_target and issue_comment events and
job condition as this repository's caller,
replacing the job's uses with:
uses: jmarrero-forge/actions/.github/workflows/jmarrero-review.yml@COMMITKeep that caller's six permission grants. Optional SAFE_OUTPUTS_PAT is
forwarded explicitly, only to apply; it never reaches the agent or the real
review submission. Keep workflow/review.toml, workflow/review-command.toml
and workflow/review.md on the caller's base branch. Automatic reviews admit
non-draft owner/member/collaborator PRs, preserving upstream's association
rule for all authors. Otherwise-unassociated bots wait unless REVIEW_BOT_IDS
lists their numeric IDs and the bounds admit their logins (including
Dependabot). Use a JSON array of numbers; Actions also coerces string IDs.
/review still requires write access through event policy.
Only admitted agent jobs enter per-PR concurrency; new automatic events
cancel the old agent, comments do not. The head is data inside the sandbox,
never executed by a privileged step. Each review is bounded to 150 requests,
500 AIC and 75 agent minutes.
AGENT_REAL_REVIEWS=true opts into checked APPROVE/REQUEST_CHANGES
submission with the job token, at the admitted head; unset is off. Enable
GitHub Actions' permission to create/approve PRs for this feature. A stale
head, cancellation or failed check cannot produce a new approval. The
compatibility review status is not a merge gate or human approval.
For a new repository in this organization, put the review caller and the
three workflow/review* files in its initial commit, and set the
variables above (copy them from an onboarded repository such as tracker)
and Actions' permission to approve pull requests when you create it. The
organization's ruleset requires an approving review on main and has no
bypass actors, but the first push to an empty repository isn't a pull
request, so the review is in place before the first one. Added later, the
onboarding pull request itself needs an approval from an organization
owner, because nothing can review it yet.
A repository whose name ends in -sandbox is for agents to iterate in
freely: the organization's approval ruleset excludes it, so its pull
requests merge without a review. When it's ready, renaming it to drop the
suffix brings it under the ruleset; the review above should be in place
before that rename.
Before migrating tracker (a separate repository), admit this wrapper's
job_workflow_ref, with the owner ids of admit/owners.json, in the
tailnet federation and inference broker, then
replace its review caller's uses as above and exercise a real review and
a synchronize cancellation. No ACL, OAuth or broker policy is changed here;
record those deployment changes in the private wiki when made. Removing the
deployment-specific pieces from agentic-job is a separate follow-up.
just test-review checks the wrapper's admission and publication boundaries;
live tailnet joins and GitHub review writes are not exercised locally.
Runs may edit .github/ here, so pull requests are reviewed by
this repository's caller of the wrapper
above, referenced locally so that it runs as on the base branch, never as
a pull request edits it, with this repository's bounds and task in
workflow/, once the repository variable
AGENT_REVIEW turns it on: jmarrero's broker admits no review from here
yet. The ruleset on main is to require its
approval, dismissed when new commits are pushed; the approval is submitted
only with the repository variable AGENT_REAL_REVIEWS=true, beside the
variables listed above. Dependabot's pull requests are reviewed only with
its ID in REVIEW_BOT_IDS. Without .github/agentic-job/merge.toml the
reviewer is told a person approves after it.
lock-new-items locks each newly
opened issue, so that only collaborators can comment on
it and agent runs on it read no outsider's comments (tracker#733). Its one
step locks the item by API with the caller's job token: no PAT, and
nothing of the item is read or run. Pull requests are not locked: a locked
PR refuses reviews from the review job token, and the supervisor only
dispatches issues. It does not cover the opener's own
text, comments in the seconds before the lock, items opened by another
workflow's job token or transferred in (no opened event), or items that
predate the caller. A repository opts in with this one
file, .github/workflows/lock.yml, as
this repository's caller but for its uses:
name: lock
on:
issues:
types: [opened]
permissions: {}
jobs:
lock:
uses: cgwalters-forge/actions/.github/workflows/lock-new-items.yml@main
permissions:
issues: writeThe same pull request exempts the file in
.github/agentic-job/workflows.toml, creating it if need be, as this
repository does: without that, workflows-check's shape check refuses every
later pull request. Its zizmor needs the ref-pin policy for our own
workflows that .github/zizmor.yml sets.
This copy follows cgwalters-forge/actions' main, and with it the agentic-job release that upstream's wrappers pin, rather than choosing versions of its own (cgwalters-forge/harness-coordination#7). It was last synced at upstream's 018f138, with agentic-job v0.6.2; nothing runs on it yet, pending jmarrero-forge/tracker#38 (the GitHub-side setup) and #39 (the first runs).
main takes pull requests rebase-merged (a squash would fold the
snapshot into our commits, and a merge commit is what this avoids), so a
sync is one pull request of two parts: a commit whose tree is upstream's main at a named commit, "Sync
with cgwalters-forge/actions main at SHA", then our own commits since the
previous such commit, replayed on it
(git cherry-pick PREVIOUS-SYNC..origin/main). Each replay merges against
the upstream tree it was made on, so it conflicts only where upstream
changed what we retarget. git diff SHA main is then exactly ours:
- the wrappers' names,
jmarrero-agentic-job.ymlandjmarrero-review.yml, which runs' identity tokens carry; - admit/owners.json and
tailscale/tailnets.json: our organizations,
with the client ID left to
AGENTIC_JOB_TAILSCALE_OAUTH_CLIENT_IDand no proxy address; - the defaults: claude, no broker address (
INFERENCE_URL), the audiencejmarrero-praxis-broker, andAGENT_REVIEWfor reviews; - the tailnet join, this repository's action at the commit the wrapper runs at rather than at main, since the broker admits the wrapper by commit;
- this repository's review bounds and caller, off until
AGENT_REVIEW.
Once a sync merges, the callers' pins (jmarrero-forge/tracker's
dispatch.yml and review.yml, jmarrero/review's review.yml) and the
broker's run-token policy move to the new commit together
(jmarrero/atomic-setup's bot/praxis-broker/README.md, "Moving the
wrapper's pin").
Licensed under either of Apache-2.0 or MIT, at your option.