Skip to content
Development
Command

/al

Run AgentLint diagnostic across all projects. Use when: user says /al, 'check all projects', 'agent lint', or '体检'.

From plugin
482 skills2 commands1 hooks
shell
$ npx -y skills add 0xmariowu/AgentLint --agent claude-code

Ships with agent-lint. Installing the plugin gets this command.

How it fires

How this command gets triggered: by you, by Claude, or both.

  • Fires itselfClaude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/al

Context preview

What this command does when you run it.

Run AgentLint diagnostic across all projects. Use when: user says /al, 'check all projects', 'agent lint', or '体检'.

Command definition

al.md
description: "Run AgentLint diagnostic across all projects. Use when: user says /al, 'check all projects', 'agent lint', or '体检'."
allowed-tools: Bash(*), Read(*), Write(*), Edit(*), Glob(*), Grep(*), Agent(*)

/al — AgentLint

Diagnose, plan, fix. One command. User presses Enter twice at most.

Flow

Step 1: Module Selection

AskUserQuestion with **defaults pre-selected** (user can press Enter to accept):

AgentLint — which checks to run?

Core (deterministic, no AI calls) — default ON:
  ☑ Findability         — can AI find what it needs?
  ☑ Instruction Quality — are your rules well-written?
  ☑ Workability         — can AI build and test?
  ☑ Continuity          — can next session pick up?
  ☑ Safety              — are secrets and CI locked down?
  ☑ Harness             — are Claude Code hooks/permissions safe?

Extended (opt-in, runtime-dependent):
  ☐ Deep Analysis       — find contradictions, dead weight, vague rules (uses AI)
  ☐ Session Analysis    — discover issues from your Claude Code session logs

[Enter to run with defaults]

**Default: all 6 core dimensions.** Extended analyzers are optional and will show as `n/a` in the output unless explicitly checked. User presses Enter → runs immediately.

Record the normalized choices in shell variables for the config write in Step 2. Core is currently all-or-nothing and defaults on; Deep/Session are the only runtime-selectable modules.

RUN_CORE=true
RUN_DEEP=false     # set true only if Deep Analysis was selected
RUN_SESSION=false  # set true only if Session Analysis was selected

Step 2: Init (first run only)

If `${CLAUDE_PLUGIN_DATA}/config.json` doesn't exist, ask with default:

Where are your projects? [~/Projects]: ↵

Press Enter → uses `~/Projects`. Save to `${CLAUDE_PLUGIN_DATA}/config.json`. Never ask for the projects root again.

After Step 1, always persist the selected scan options back into the same config file. The scan and verify steps must read this file instead of relying on stale shell variables; otherwise the config is dead state and Deep/Session choices are ignored.

CONFIG_DIR="${CLAUDE_PLUGIN_DATA:-$HOME/.al}"
CONFIG_FILE="$CONFIG_DIR/config.json"
mkdir -p "$CONFIG_DIR"

if [ ! -f "$CONFIG_FILE" ]; then
  PROJECTS_ROOT_INPUT="${PROJECTS_ROOT_INPUT:-$HOME/Projects}"
  node -e '
    const fs = require("fs");
    const file = process.argv[1];
    const projectsRoot = process.argv[2];
    fs.writeFileSync(file, JSON.stringify({
      projects_root: projectsRoot,
      modules: { core: true, deep: false, session: false }
    }, null, 2) + "\n");
  ' "$CONFIG_FILE" "$PROJECTS_ROOT_INPUT"
fi

CONFIG_TMP="$(mktemp "$CONFIG_DIR/config.XXXXXX")"
node -e '
  const fs = require("fs");
  const [file, out, core, deep, session] = process.argv.slice(1);
  const cfg = JSON.parse(fs.readFileSync(file, "utf8"));
  cfg.modules = {
    ...(cfg.modules || {}),
    core: core === "true",
    deep: deep === "true",
    session: session === "true"
  };
  fs.writeFileSync(out, JSON.stringify(cfg, null, 2) + "\n");
' "$CONFIG_FILE" "$CONFIG_TMP" "$RUN_CORE" "$RUN_DEEP" "$RUN_SESSION"
mv "$CONFIG_TMP" "$CONFIG_FILE"

Step 3: Core scan (no interaction, no scoring yet)

`scanner.sh`'s `--project-dir` is single-project. For `/al`'s multi-project flow, use the env-var path so the scanner auto-discovers every git repo under `PROJECTS_ROOT`:

CONFIG_FILE="${CLAUDE_PLUGIN_DATA:-$HOME/.al}/config.json"
PROJECTS_ROOT="$(jq -er '.projects_root' "$CONFIG_FILE")"
RUN_DEEP="$(jq -r '.modules.deep // false' "$CONFIG_FILE")"
RUN_SESSION="$(jq -r '.modules.session // false' "$CONFIG_FILE")"
AL_DIR="${CLAUDE_PLUGIN_ROOT}"
RUN_ROOT="${CLAUDE_PLUGIN_DATA:-$HOME/.al}/runs"
mkdir -p "$RUN_ROOT"
RUN_DIR="$(mktemp -d "$RUN_ROOT/$(date +%Y%m%d)-XXXXXX")"
PROJECTS_ROOT="$PROJECTS_ROOT" bash "$AL_DIR/src/scanner.sh" > "$RUN_DIR/scan.jsonl"

**Do NOT run scorer yet.** If Deep or Session modules were selected in Step 1, they produce additional JSONL records that must be merged with `scan.jsonl` before scoring. Scoring prematurely here would lock in a core-only score and force a re-score later, producing inconsistent intermediate reports.

`mkdir -p "$RUN_ROOT"` is required because `mktemp -d` fails if the parent directory doesn't exist — which is exactly the state on a user's first `/al` invocation after plugin install.

`RUN_DIR` replaces the old `/tmp/al-*.jsonl` paths so concurrent Claude sessions on the same machine don't overwrite each other's runs.

Step 3b: Extended analyzers (conditional)

If `RUN_DEEP` read from `${CLAUDE_PLUGIN_DATA}/config.json` is `true`, run the Deep Analysis flow now (see "Deep Analysis" section further below) to produce `$RUN_DIR/deep.jsonl`.

If `RUN_SESSION` read from `${CLAUDE_PLUGIN_DATA}/config.json` is `true`, run the Session Analysis flow to produce `$RUN_DIR/session.jsonl`.

Neither produces output when not selected — that's fine, the merge step handles a missing file gracefully.

Step 3c: Merge + score + plan (no interaction)

: > "$RUN_DIR/combined.jsonl"
cat "$RUN_DIR/scan.jsonl" >> "$RUN_DIR/combined.jsonl"
[ -f "$RUN_DIR/deep.jsonl" ]    && cat "$RUN_DIR/deep.jsonl"    >> "$RUN_DIR/combined.jsonl"
[ -f "$RUN_DIR/session.jsonl" ] && cat "$RUN_DIR/session.jsonl" >> "$RUN_DIR/combined.jsonl"

node "$AL_DIR/src/scorer.js" "$RUN_DIR/combined.jsonl" > "$RUN_DIR/scores.json"
node "$AL_DIR/src/plan-generator.js" "$RUN_DIR/scores.json" > "$RUN_DIR/plan.json"

Scoring happens **once**, after every selected analyzer has written its JSONL. `score_scope` is `core+extended` exactly when at least one of `deep.jsonl` / `session.jsonl` is present, and `core` otherwise — no coercion, no re-scoring.

Step 4: Present Scores (no interaction)

Read `$RUN_DIR/scores.json` and present. The `(core)` suffix on the total line appears when Deep/Session did not run — it signals that the score is averaged over the 6 core dimensions only. Extended dimens

Read more
Read it on GitHub ↗

Showing the first part of this file.

Ships withagent-lint

The linter for your agent harness. Works with Claude Code, Codex, and Cursor.

Get the whole plugin, auto-invoked
Stats
48
Stars
0
Views
3
Forks
Active
Maintenance
Shell
Language
MIT
License
10d ago
Last commit
4mo ago
Created

Repo: 0xmariowu/AgentLint

More commands in this plugin
See everything inside