Watch repository and dependency changes
Turn repository drift and upstream releases into evidence for new issues.
Repository care and release watching feed the same intake process. Each monitor records a signal and an assessment. A person decides whether it warrants an issue, adds acceptance criteria, and marks the issue ready.
This module can run independently of the issue walkthrough. Complete agent setup and run it from the repository you want to inspect.
These monitors gather signals. The inspector connects them to failed checks and earlier decisions before proposing an improvement. Use skill evaluations when the change concerns the instructions agents follow.
Watch repository instructions
The first monitor below watches AGENTS.md and CLAUDE.md. It asks an agent
to read the changed instructions and relevant Git history, then stores its
findings in an artifact. This is the repository caretaker’s role in the factory.
Watch upstream releases
The second monitor polls Bun’s release metadata. It compares release tags before asking for an assessment, so unrelated metadata changes do not repeat the agent work. Change the source for another dependency.
Create .foundry/marbles/maintenance.ts:
Complete maintenance.ts
import { agent, artifact, monitor } from "@foundry.sh/marbles";
const signals = artifact({
name: "Factory maintenance signals",
type: "application/json",
});
const assessor = agent({
prompt:
"Assess this change against the repository. Describe the evidence, whether an issue is warranted, and suggested acceptance criteria. Do not edit files or create an issue.",
});
monitor("**/{AGENTS,CLAUDE}.md")
.every("1m")
.do(async ({ files, agents, report, run }) => {
const session = await agents.session(assessor);
const reply = await session.generate(
`Inspect instruction drift and relevant Git history: ${JSON.stringify(files)}`
);
await report.artifact(
signals,
{
"assessment.md": reply.text,
"signal.json": JSON.stringify(
{ files, runId: run.id, source: "repository instructions" },
null,
2
),
},
{ body: reply.text, title: "Repository instruction assessment" }
);
});
const releaseTag = (value: unknown): string | undefined => {
if (typeof value !== "object" || value === null || !("tag_name" in value)) {
return;
}
return typeof value.tag_name === "string" ? value.tag_name : undefined;
};
monitor("https://api.github.com/repos/oven-sh/bun/releases/latest")
.every("6h")
.do(async ({ change, agents, report, run }) => {
if (change.kind !== "http") {
return;
}
const tag = releaseTag(change.current);
if (!tag || tag === releaseTag(change.previous)) {
return;
}
const session = await agents.session(assessor);
const reply = await session.generate(
`Assess Bun ${tag} for this repository. Read its release notes before proposing upgrade work.`
);
await report.artifact(
signals,
{
"assessment.md": reply.text,
"signal.json": JSON.stringify(
{ runId: run.id, source: "Bun release", tag },
null,
2
),
},
{ body: reply.text, title: `Bun ${tag} assessment` }
);
});
Bring a signal into the cycle
Run marbles list to find each monitor key, then marbles roll <key> for
one poll. The first poll sees the existing files or release as a change.
Read the assessment in the Feed before enabling the monitor loop.
When an assessment warrants work, create or update an issue with the source, artifact version, relevant findings, and acceptance criteria. For a release, include the release tag. For instruction drift, identify the changed files and repository revision. That evidence becomes part of the issue snapshot and stays available to the implementer and reviewer.
The Factory maintenance signals artifact keeps a version per assessment.
Each report.artifact(...) call supplies the assessment as its Feed body,
so a person can read it there. The saved signal.json and assessment.md
retain the evidence for the issue and later runs.
Its latest version is the most recent signal, so retain the specific
version ID in the issue. It is not a queue of all unhandled signals.
A failed handler can observe the same change again. Check for an existing issue before filing another one. Dry execution still reads files and sends the HTTP request, while it substitutes the agent turn.
Next: Schedule updates and reports.