Time-Based /loop Workflows
Build a dependency health monitor using Claude Code /loop cadence-driven automation.
Introduction
30 Second Summary
Every Node.js project depends on third-party packages that update constantly. Without regular check-ins, outdated versions quietly pile up alongside security vulnerabilities you never see coming.
In this project, you will build a dependency health monitoring system powered by Claude Code. It monitors your dependencies on a recurring schedule and hands off targeted fixes to a goal-driven workflow.
What You'll Build
You run a single command, step away from the terminal, and two minutes later Claude Code delivers a structured dependency health report, all on its own.
By the end of this project, you'll have:
- A recurring dependency monitor powered by /loop that checks your packages on a fixed cadence and flags version drift without modifying any code.
- A sandboxed monitoring skill backed by disallowed-tools enforcement, ensuring the loop stays read-only even in auto mode.
- A two-phase workflow combining cadence-driven /loop detection with condition-driven /goal remediation to upgrade packages safely.
- Secret Mission: security vulnerability scanning with npm audit and a desktop notification hook that alerts you when each monitoring iteration finishes.
Are there any prerequisites?
This project follows Project 1 (Goal Condition Engineering) and Project 2 (Custom Stop-Hook Evaluators) in the Claude Code loop engineering series. You need Claude Code installed with an API key or Max subscription, plus Node.js 24 LTS.
Before We Start
You are about to build a dependency health monitor that runs autonomously inside Claude Code. Before writing a single file, lock in the problem you are solving: why periodic, bounded monitoring matters, and what can go wrong when you let an autonomous agent act without guardrails.
Scaffold a Demo Project with Outdated Dependencies
You know why periodic, bounded monitoring matters. Now you need something to monitor.
In this step, you will scaffold a Node.js project with intentionally outdated dependencies. Pinning old versions of express, lodash, and axios guarantees that npm outdated always finds problems, giving you a deterministic test bed for every /loop experiment you run later.
In this step, get ready to:
- Create a project with package.json, an Express app, and a test file.
- Install the pinned dependencies and initialize a Git repository with a clean baseline commit.
- Configure CLAUDE.md and verify all three packages show as outdated.
Create the project files
Every /loop experiment in this project needs npm outdated to return consistent results. Pinning specific older versions in package.json makes that happen.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Terminal and press Enter to open it.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir dep-health-monitor
cd dep-health-monitor
- Create a new file called package.json in the dep-health-monitor folder with the following content:
{
"name": "dep-health-monitor",
"version": "1.0.0",
"description": "Demo project for dependency health monitoring with Claude Code /loop",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "node --test test/"
},
"dependencies": {
"express": "4.18.2",
"lodash": "4.17.20",
"axios": "1.6.0"
}
}
What does this file do?
The dependencies block pins three packages to specific older versions: express at 4.18.2, lodash at 4.17.20, and axios at 1.6.0. These are all behind the latest releases, so npm outdated will always find something to report.
The test script uses node --test test/, which is Node's built-in test runner. No extra testing library needed.
- Save package.json.
- Now create a file called index.js in the same folder. Start with the imports and the /health endpoint:
// Import the three intentionally outdated dependencies
const express = require('express');
const _ = require('lodash');
const axios = require('axios');
// Create the Express app and set the port
const app = express();
const PORT = 3000;
// Health endpoint that reports installed package versions
app.get('/health', (req, res) => {
res.json({
status: 'ok',
versions: {
express: require('express/package.json').version,
lodash: require('lodash/package.json').version,
axios: require('axios/package.json').version
}
});
});
What does this code do?
- The three require() calls pull in the pinned versions of Express, lodash, and axios so they are active in the project.
- The /health endpoint reads each package's actual installed version from its package.json at runtime. This lets you verify which versions are live without checking node_modules manually.
- Confirm your two files exist by running:
ls
You should see index.js and package.json in the output.
Only see one file?
- Make sure you saved both files. Check that you are inside the dep-health-monitor folder by running pwd. The path should end with dep-health-monitor.
- If you accidentally created a file in the wrong folder, move it with mv or delete it and recreate it inside dep-health-monitor.
Why are my files missing from the project folder?
- Add the /deps endpoint, the server startup logic, and the module export to the bottom of index.js:
// List all dependencies from package.json
app.get('/deps', (req, res) => {
const deps = Object.keys(require('./package.json').dependencies);
res.json({ dependencies: deps, count: deps.length });
});
// Start the server only when run directly (not when imported for tests)
if (require.main === module) {
app.listen(PORT, () => {
console.log(`Dep health monitor running on port ${PORT}`);
});
}
// Export the app so tests can import it
module.exports = app;
What does this code do?
- /deps reads the dependency names straight from package.json and returns them as JSON. This gives Claude another way to inspect the project.
- The require.main === module check starts the server only when you run the file directly. When the test file imports it, the server stays off so tests do not conflict with a running process.
- Save index.js.
✔️ Awesome, I've got everything!
Great. Double check you have saved index.js before moving on.
ⓧ I'd like to double check the full code
Here is the complete index.js. Make sure your file matches this exactly:
const express = require('express');
const _ = require('lodash');
const axios = require('axios');
const app = express();
const PORT = 3000;
app.get('/health', (req, res) => {
res.json({
status: 'ok',
versions: {
express: require('express/package.json').version,
lodash: require('lodash/package.json').version,
axios: require('axios/package.json').version
}
});
});
app.get('/deps', (req, res) => {
const deps = Object.keys(require('./package.json').dependencies);
res.json({ dependencies: deps, count: deps.length });
});
if (require.main === module) {
app.listen(PORT, () => {
console.log(`Dep health monitor running on port ${PORT}`);
});
}
module.exports = app;
- Create a test directory inside dep-health-monitor by running:
mkdir test
- Create a file called health.test.js inside the test folder with the following content:
const { describe, it } = require('node:test');
const assert = require('node:assert');
const app = require('../index');
// Verify the Express app exports correctly
describe('health endpoint', () => {
it('should export the express app', () => {
assert.ok(app);
assert.strictEqual(typeof app.listen, 'function');
});
});
What does this test do?
This test uses Node's built-in test runner (node:test) to verify that index.js exports a working Express app with a listen function. When you use /goal for remediation later, this test is how Claude will verify that upgrades do not break anything.
- Save test/health.test.js.
Install dependencies and initialize git
- Install the pinned dependency versions by running:
npm install
You should see output listing the installed packages. npm may show warnings about vulnerabilities. That is expected since you pinned older versions on purpose.
Seeing a network or permission error?
- Check your internet connection. npm install needs to download packages from the npm registry.
- If you see a permission error, make sure you are inside the dep-health-monitor folder (run pwd to check) and that your package.json has valid JSON syntax.
Why is npm install failing in my project?
- Verify the test suite passes by running:
npm test
You should see output showing 1 test passed with 0 failures. This confirms the app exports correctly and Node's built-in test runner is working.
Test failing?
- Check that index.js ends with module.exports = app; so the test can import it.
- Make sure health.test.js is inside the test/ folder, not in the project root.
Why is my Node.js test failing?
- Initialize a Git repository by running:
git init
- Stage all files and make your initial commit by running these commands:
git add .
git commit -m "Initial commit: pinned outdated dependencies"
You should see a commit summary listing the files you created. This baseline commit is important. In a later step, you will need to revert to this exact state after seeing what an unbounded loop does to your code.
Configure CLAUDE.md and verify
Claude Code reads a CLAUDE.md file in your project root to learn conventions about how to work with your codebase. Setting these rules now prevents Claude from making assumptions during autonomous loops.
- Create a file called CLAUDE.md in the dep-health-monitor folder with the following content:
# Dependency Health Monitor
This is a demo Node.js project for practicing Claude Code /loop workflows.
## Project Conventions
- Use `npm outdated` to check dependency freshness
- Use `npm audit` to check for security vulnerabilities
- Use `npm test` to run the test suite before committing changes
- Do not upgrade dependencies unless explicitly asked
- Report findings in a structured format: package name, current version, latest version, severity
Why does CLAUDE.md matter for loops?
The line "Do not upgrade dependencies unless explicitly asked" is the first layer of defense against unbounded autonomous action. When Claude runs a monitoring loop, it reads CLAUDE.md at the start of each session and respects these conventions.
You will see later that conventions alone are not enough to guarantee read-only behavior. That is where disallowed-tools enforcement comes in.
- Save CLAUDE.md.
Before you run the next command, what do you think npm outdated will show? You pinned three packages to older versions. How many should appear?
- Verify all three packages show as outdated by running:
npm outdated
You should see a table with columns for Package, Current, Wanted, and Latest. All three packages (axios, express, and lodash) should appear with their pinned versions under Current and newer versions under Latest.
What should I see?
The output lists each outdated package on its own row. express shows 4.18.2 as the current version with a higher number under Latest. lodash shows 4.17.20, and axios shows 1.6.0. If all three appear, your test environment is deterministic and ready for monitoring experiments.
Not seeing all three packages?
- Make sure you ran npm install first. npm outdated compares installed versions against the registry, so it needs node_modules to exist.
- Check that your package.json lists all three dependencies with exact versions (no ^ or ~ prefix). Exact pins like "4.18.2" ensure the Wanted column differs from Latest.
Why does npm outdated not show my dependencies as outdated?
Your demo project is locked in. Every time you run npm outdated from here on, you will get the same three packages with the same version drift. Next up, you will run a one-shot dependency audit with Claude and feel exactly why a manual check is not enough.
Run a One-Shot Dependency Audit
Your demo project is locked and loaded with three dependencies pinned to older versions. Every run of npm outdated flags them. Now it's time to put Claude Code to work analyzing that version drift.
In this step, you'll ask Claude to perform a dependency health audit. Claude will run npm outdated, parse the results, and present a structured report summarizing exactly where your project stands.
In this step, get ready to:
- Ask Claude Code to produce a structured dependency health report.
- Observe the one-shot report listing outdated packages with their current vs latest versions.
- Understand why a manual audit leaves a gap that needs automation.
Prompt Claude for a manual audit
In the last step, you ran npm outdated yourself and saw the raw output. Now let Claude do the same analysis and present the results as a clean, structured summary you could hand to a teammate.
- Switch to your Claude Code session in the terminal. Make sure you are inside the dep-health-monitor/ directory.
- Type this prompt into Claude Code:
Check this project's dependency health by running npm outdated and summarizing the results as a structured report. For each outdated package, show the package name, current version, and latest version.
Before you press Enter, think about this: what do you expect Claude will find when it checks the three dependencies you pinned in package.json?
- Press Enter to send the prompt.
Watch Claude run the command, parse the output, and present a clear summary. You should see all three packages listed as outdated: express, lodash, and axios, each with the pinned version you installed and the latest version available on npm.
What does Claude do with this prompt?
Claude reads your CLAUDE.md and sees the convention to use npm outdated for freshness checks. It runs the command, captures the tabular output, and reformats it into a readable report.
The report tells you which packages are behind and by how much. For example, a patch bump (4.17.20 to 4.17.21) is less urgent than a major bump (4.x to 5.x).
Not seeing a structured report?
- Make sure Claude Code is running from inside the dep-health-monitor/ directory. If Claude can't find package.json, it has nothing to audit.
- If Claude asks for permission to run the command, approve it. Claude needs to execute npm outdated to produce the report.
- If the output looks different from what you expected, that's OK. Claude may format the report in its own style. The key thing is that all three packages appear with version information.
Ask Claude for help debugging.
Note the limitation
The report Claude produced is accurate. It tells you exactly which packages are behind and by how much. But it is a snapshot frozen in time.
If a new vulnerability is disclosed tomorrow, or a dependency releases a breaking change next week, you will not know until you manually re-run the audit. Your project's health drifts in silence between checks.
Why is a one-shot audit not enough?
Dependency health is not a one-time question. New versions, security patches, and breaking changes land continuously. A single audit answers "how are things right now?" but not "how are things tomorrow?" or "how were things last Tuesday?"
This is the gap that /loop is designed to fill. Instead of relying on your memory to re-run the check, /loop automates it on a fixed cadence so monitoring happens whether you remember or not.
You've seen what a manual audit looks like and felt its limitation firsthand. In the next step, you'll hand this job to /loop and watch what happens when an autonomous loop runs with too much freedom.
Introduce /loop for Cadence-Driven Monitoring
Your dependency health report from the last step captured a snapshot of the project's health. It was accurate, but frozen in time. If a new vulnerability lands tomorrow, you will not know until you remember to run the audit again.
Claude Code's /loop command automates a prompt on a fixed cadence, solving the "remembering" problem. In this step, you will start a /loop and discover firsthand what happens when a recurring prompt is too broad and auto mode is on.
In this step, get ready to:
- Switch to auto mode and start a /loop with a broad prompt.
- Watch Claude make unintended changes to your project files.
- Stop the loop, revert all changes, and understand why guardrails matter.
Switch to auto mode and start a broad loop
In Claude Code, auto mode approves tool calls without asking you first. Combined with /loop, this means Claude can act on its own every time the loop fires, with no human approval in between.
- In your Claude Code terminal, press Shift+Tab to cycle to auto mode.
- Confirm you see the auto mode indicator in the status bar.
What is auto mode?
Auto mode removes the per-tool-call approval prompt. Claude reads files, writes files, and executes commands without stopping to ask you.
This is useful for trusted workflows where you have reviewed the prompt and are confident in Claude's scope. It becomes dangerous when the prompt is too broad.
Before running the next command, pause and think. You are about to tell Claude to "check the project dependencies and fix any issues you find" on a 2-minute recurring loop, with auto mode on. What do you expect to happen?
- Start the loop by typing this into Claude Code:
/loop 2m check the project dependencies and fix any issues you find
What does this command do?
- /loop 2m tells Claude to re-run the prompt every 2 minutes.
- The rest is the prompt itself. Notice it says "fix." In auto mode, Claude will act on that word without asking for permission.
- Watch the first iteration fire. Claude runs npm outdated, finds the three outdated packages, and because the prompt says "fix," it begins acting on them.
Observe the unintended changes
- Watch Claude's output during the first or second iteration.
Claude detects the outdated packages and follows the "fix" instruction. It begins upgrading them: editing package.json, running npm install, possibly running tests and committing.
These are changes you never explicitly authorized for a monitoring loop. The monitoring loop has become an action loop.
This is the designed obstacle
You are watching exactly what happens when detection and action are conflated in a single prompt. The problem is not /loop itself. The problem is the combination of a prompt that says "fix," auto mode that approves everything, and a recurring schedule that fires without human review.
Stop the loop and reset
- Press Esc to stop the loop while it is waiting for the next iteration.
- See exactly what Claude changed by running this in your terminal:
git diff
You will see modifications to package.json and possibly other files. These are the unintended side effects of the broad prompt combined with auto mode.
- Restore the project to its original state by running:
git checkout . && git clean -fd
What do these commands do?
- git checkout . reverts all modified tracked files back to the last commit.
- git clean -fd removes any untracked files and directories that the loop may have created.
- Return to your Claude Code terminal and press Shift+Tab to switch back to manual mode.
- Confirm the project is restored by running:
npm outdated
You should see express, lodash, and axios listed as outdated again, exactly as they were before the loop ran. The project is back to its clean baseline.
What just happened?
A recurring prompt that conflates detection with action is dangerous in auto mode. Your /loop kept firing and Claude kept "fixing" because nothing stopped it from acting.
The fix is to separate what the loop detects from what it does about the findings. In the next step, you will enforce that separation at the tool level.
Loop didn't make any changes?
- Make sure you switched to auto mode with Shift+Tab before starting the loop. In manual mode, Claude asks for approval before each action and may not proceed.
- Check that your prompt included the word "fix." Without it, Claude may only report findings rather than act on them.
- Wait for the full 2-minute interval to elapse. The first iteration starts after the interval, not immediately.
Why didn't my /loop make changes in auto mode?
The lesson is clear. An unbounded loop with a broad prompt and auto mode is a recipe for unintended changes. Next, you will craft safe recurring prompts and lock down the loop with disallowed-tools enforcement.
Craft Safe Recurring Prompts and Bound the Loop
You just watched an unbounded /loop rewrite your project files because the prompt combined detection with action. The word "fix" was all it took for Claude to go from reporting outdated packages to upgrading them on its own.
The solution is to separate detection from action at two levels. First, you will rewrite the prompt to request reporting only. Then, you will enforce that boundary at the tool level with a custom skill that physically blocks file-modification tools.
In this step, get ready to:
- Rewrite the monitoring prompt to separate detection from action.
- Create a /dep-health skill with disallowed-tools enforcement.
- Run the bounded loop and manage scheduled tasks with CronList and CronDelete.
Rewrite the prompt for read-only monitoring
The naive prompt from Step 3 said "check the project dependencies and fix any issues you find." That single word "fix" gave Claude license to edit files, run installs, and commit changes. A safe recurring prompt removes the action clause entirely.
- Return to your Claude Code session in the dep-health-monitor project.
- Type the following bounded prompt and press Enter:
Run npm outdated, report the findings in a structured format showing package name, current version, and latest version. Do not modify any files.
Claude runs npm outdated, parses the output, and presents a clean report. No files are touched.
Why prompt-level instructions alone are not enforcement
The bounded prompt works here because Claude follows the instruction in a one-shot context. During long autonomous runs, however, Claude can drift from prompt-level instructions. A prompt says "please don't" while tool-level enforcement says "you can't."
In the next substep, you will create a skill that removes the Write and Edit tools entirely, making read-only behavior structural rather than requested.
Create a /dep-health skill with disallowed-tools
Claude Code skills are reusable instructions stored as Markdown files with YAML frontmatter. The disallowed-tools field in the frontmatter removes specific tools from Claude's available pool while the skill is active.
- Open a separate terminal tab or window.
- Navigate to your dep-health-monitor directory and create the skill folder structure by running this command:
mkdir -p .claude/skills/dep-health
- Confirm the directory was created by running:
ls .claude/skills/dep-health
The directory should exist and be empty. Now create the skill file inside it.
- Open .claude/skills/dep-health/SKILL.md in your text editor and paste the following content:
---
description: Run a read-only dependency health check. Reports outdated packages and version drift without modifying any files.
disallowed-tools: Write, Edit
---
# Dependency Health Check
Run the following checks and report findings. Do NOT modify any files.
1. Run `npm outdated --json` and parse the output
2. For each outdated package, report:
- Package name
- Current version (installed)
- Wanted version (semver-compatible)
- Latest version (newest available)
- Whether the upgrade is a major, minor, or patch bump
3. Summarize: total packages checked, number outdated, number with major upgrades available
Format the output as a clear status report. If everything is current, say so in one line.
What does this skill file do?
The YAML frontmatter between the --- markers configures the skill. description tells Claude when to match this skill to your request. disallowed-tools: Write, Edit removes the Write and Edit tools from Claude's pool while the skill is active.
The body below the frontmatter is the prompt Claude follows. It instructs Claude to run npm outdated --json, parse the results, and report findings in a structured format. The restriction clears when you send your next message after the skill finishes.
- Save SKILL.md.
- Confirm the file exists by running:
ls .claude/skills/dep-health/
You should see SKILL.md listed in the output.
Don't see SKILL.md?
Make sure you created the file inside .claude/skills/dep-health/ and not in the project root. The directory starts with a dot, so it is hidden by default in most file browsers.
help me find where my SKILL.md file ended up
✔️ Awesome, I've got everything!
Great. Make sure you have saved SKILL.md and switch back to your Claude Code terminal for the next substep.
ⓧ I'd like to double check the full code
Here is the complete SKILL.md file. Confirm your version matches character for character:
---
description: Run a read-only dependency health check. Reports outdated packages and version drift without modifying any files.
disallowed-tools: Write, Edit
---
# Dependency Health Check
Run the following checks and report findings. Do NOT modify any files.
1. Run `npm outdated --json` and parse the output
2. For each outdated package, report:
- Package name
- Current version (installed)
- Wanted version (semver-compatible)
- Latest version (newest available)
- Whether the upgrade is a major, minor, or patch bump
3. Summarize: total packages checked, number outdated, number with major upgrades available
Format the output as a clear status report. If everything is current, say so in one line.
Run the bounded loop and manage tasks
The skill is in place. Now you will prove that the bounded loop reports without modifying files, even in auto mode where every tool call is approved automatically.
- Switch back to your Claude Code terminal.
- Press Shift+Tab to cycle permission modes until the status bar shows auto mode.
- Start the bounded loop by typing this command and pressing Enter:
/loop 2m /dep-health
What does this command do?
/loop 2m tells Claude Code to re-run the prompt every 2 minutes. /dep-health invokes your custom skill, which loads the SKILL.md instructions and applies the disallowed-tools restriction. Each iteration re-invokes the skill, re-applying the Write and Edit restriction.
Watch the first iteration fire. Claude runs npm outdated and presents a structured report listing express, lodash, and axios with their current and latest versions.
Before you check for changes, predict: do you think git diff will show any modifications this time?
- After the first iteration completes, type the following to check for changes:
run git diff to show me if any files changed
You should see no output from git diff. The disallowed-tools restriction blocked Write and Edit entirely, so Claude could not modify any files even though auto mode approved every other tool call.
Why disallowed-tools beats a polite prompt
In the previous step, the prompt said "fix" and Claude obliged. This time, even if the skill instructions had accidentally included an action clause, Claude physically cannot call Write or Edit. The enforcement is structural: the tools are removed from Claude's available pool, not just discouraged.
- Now ask Claude to list your scheduled tasks by typing:
what scheduled tasks do I have?
Claude uses CronList to display your active scheduled task. You will see an entry with an 8-character task ID, the 2-minute cron schedule, and the /dep-health prompt.
- Cancel the scheduled task by asking Claude to delete it. Reference the task ID from the CronList output:
cancel that scheduled task
Claude uses CronDelete to remove the task. The loop stops firing.
- Press Shift+Tab to cycle back to manual mode. The status bar should show the manual mode indicator.
The full lifecycle of a scheduled task
You just walked through create, monitor, and delete. /loop used CronCreate behind the scenes to register a recurring cron job. CronList showed you the active task with its ID. CronDelete cancelled it by that ID. A session can hold up to 50 scheduled tasks at once, and recurring tasks automatically expire after 7 days.
Loop didn't fire or skill not found?
If Claude says it cannot find the /dep-health skill, make sure your SKILL.md file is at .claude/skills/dep-health/SKILL.md inside the dep-health-monitor project root. The path must be exact. Also confirm the file starts with --- on the very first line with no blank lines above it.
help me troubleshoot why Claude Code can't find my /dep-health skill
You now have a monitoring loop that is structurally safe. No matter how long it runs or what mode it operates in, Claude cannot modify your files. Next up, you will combine this cadence-driven detection with condition-driven remediation using /goal.
Combine /loop Detection with /goal Remediation
Your /dep-health skill now monitors dependencies on a recurring cadence without touching a single file. Detection is solved. But a report sitting in your terminal does not fix a vulnerable package.
/loop excels at periodic detection, but it has no concept of "done." /goal excels at driving bounded work to a defined end state. In this step, you will combine them into a two-phase workflow: monitoring discovers the problem, then goal-driven work fixes it.
In this step, get ready to:
- Identify a remediation target from the monitoring output.
- Use /goal to drive a bounded dependency upgrade with test verification.
- Compare when to use cadence-driven /loop vs condition-driven /goal.
Identify a remediation target from loop output
Before you can fix anything, you need a fresh snapshot of what is outdated. The /dep-health skill gives you exactly that.
- If you have any loops still running, press Esc to stop them before continuing.
- Run the /dep-health skill one more time to get a fresh dependency report:
/dep-health
You should see all three outdated packages listed with their current and latest versions.
- Identify lodash at version 4.17.20 as your remediation target. It has a known vulnerability and the version drift is significant.
Why target lodash specifically?
Lodash 4.17.20 has known security vulnerabilities. It also makes a clean, bounded target: one package, one upgrade, one test run. That is the perfect shape for a /goal condition.
Use /goal for bounded remediation
The /dep-health skill found the problem. Now you need a different primitive to fix it.
/goal drives turn-by-turn work toward a defined end state. After each turn, an evaluator checks whether the condition is met. Once it confirms the work is done, the goal clears automatically.
- Start the bounded remediation by running this /goal command:
/goal update lodash to its latest version, run npm test to verify nothing breaks, then commit the change with a descriptive message. Stop after 10 turns if not complete.
What does this /goal command do?
- The condition describes the desired end state: lodash upgraded, tests passing, change committed.
- The evaluator checks this condition after every turn. When it confirms all three parts are satisfied, the goal clears.
- "Stop after 10 turns" bounds the work so Claude does not run indefinitely if something goes wrong.
Watch Claude work through the remediation. It will update lodash in package.json, run npm install, execute npm test, and commit the change. The evaluator confirms completion and clears the goal.
Now verify the result yourself. Before you run the next command, think about what npm outdated should show. Should lodash still appear in the output?
- Confirm the upgrade by running:
npm outdated
Lodash no longer appears in the outdated list. Express and axios still show as outdated because you only targeted lodash for this remediation cycle.
- Confirm tests still pass by running:
npm test
All tests pass. The /goal evaluator already verified this during the remediation, but running it yourself confirms the upgrade did not break anything.
Lodash still showing as outdated?
- Check whether the /goal actually completed. Look at the evaluator's final message. If it says "impossible" or hit the 10-turn limit, the upgrade may not have finished.
- Run git log --oneline -3 to check whether a commit was made. If there is no new commit, the goal did not reach the commit step.
- If the goal stalled, run the /goal command again. It will pick up from the current state and continue toward the condition.
My /goal didn't complete the lodash upgrade. What should I check?
Compare cadence-driven vs condition-driven patterns
You have now used both loop primitives for two different jobs. The difference between them is the answer to one question: what triggers the next iteration?
When do I use /loop vs /goal?
/loop is cadence-driven. The next iteration fires when a time interval elapses. It has no concept of "done" beyond you stopping it with Esc or the 7-day automatic expiry. Use it for ongoing monitoring where "done" does not apply.
/goal is condition-driven. The next turn starts immediately after the previous one finishes. An evaluator checks after each turn and stops when the condition is met or judged impossible. Use it for bounded tasks with a clear success condition.
The chaining pattern: use /loop to detect problems on a schedule. When the report reveals something worth fixing, stop the loop, then use /goal to drive the fix to completion.
Your two-phase workflow is complete. /loop monitors on a schedule, /goal drives fixes to completion. If you want to take it further, the Secret Mission adds security vulnerability scanning with npm audit and desktop notifications that ping you when each monitoring iteration finishes.
Secret mission
Add Security Scanning and Notification Hooks
Your monitoring loop catches version drift, but what about security vulnerabilities? In this mission, you will extend your /dep-health skill with npm audit scanning, customize the default /loop behavior with a loop.md file, and wire up a macOS desktop notification so you know when each iteration completes without watching the terminal.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally, so there are no ongoing cloud costs. Decide whether to keep your resources, pause them to come back later, or delete them entirely.
Resources you used:
- The dep-health-monitor/ project directory on your Desktop (includes source files, node_modules/, skill files, and a git repository).
- A Notification hook added to ~/.claude/settings.json.
Keep everything running
No action needed. Choose this if you want to keep experimenting with /loop cadences or apply the patterns you built to other projects.
- Try different /loop intervals, or omit the time argument entirely to let Claude decide the cadence dynamically.
- Apply the /dep-health skill to your own Node.js projects by copying the .claude/skills/dep-health/ directory into them.
- Adapt the bounded-skill + /loop pattern for other monitoring tasks like log watching, API health checks, or CI status polling.
Pause - I'll come back to this later
Stop any running loops to avoid consuming API credits, but keep your project files on disk for later.
- Press Esc in Claude Code to stop any active /loop.
- Starting a new Claude Code conversation also stops all scheduled tasks automatically, since loops are session-scoped.
- Your project files, skill definitions, and loop.md will stay on disk until you return.
Delete - I don't want to use this again
Remove all project files and revert any settings changes you made during this project.
- Delete the dep-health-monitor project directory.
macOS
rm -rf ~/Desktop/dep-health-monitor
Windows
Remove-Item -Recurse -Force "$env:USERPROFILE\Desktop\dep-health-monitor"
- Remove the Notification hook from ~/.claude/settings.json. Open the file in your text editor and delete the entire Notification entry from the hooks object.
- If the Notification hook was the only entry in ~/.claude/settings.json, you can replace the file contents with {} or delete the file entirely.
Nice Work!
Nice Work!
You just built a dependency health monitoring system that separates detection from action, all powered by Claude Code's autonomous loop primitives. You know how to keep recurring workflows safe, bounded, and useful.
You've learned how to:
- Experience the dangers of unbounded autonomous loops firsthand and craft safe recurring prompts backed by a custom skill with disallowed-tools enforcement to keep monitoring read-only.
- Combine /loop for cadence-driven detection with /goal for condition-driven remediation in a two-phase workflow that detects problems on a schedule and fixes them to a defined end state.
- Manage the full lifecycle of scheduled tasks with CronCreate, CronList, and CronDelete, knowing when to reach for time-interval monitoring vs bounded condition-driven work.
- (Secret Mission) Added npm audit security scanning, customized default monitoring with loop.md, and wired up a Notification hook for passive desktop alerts.
Ready to quiz yourself?