Claude Code terminal simulator
This is a bounded teaching simulation, not Claude Code. Nothing is executed, no credential is requested or read, and no terminal transcript is written to your device.
Blueprint coverage
This surface serves these published sub-skills. The percentages come from the blueprint.
- Claude Code Operation3.1% of the exam
Simulated terminal
This is a simulation. It does not run Claude Code, execute input, request a credential, or send data.
This visit starts with an empty transcript. Nothing typed here is stored on this device.
- No simulated command has run in this visit.
Guided tasks
Task completion is neither a score nor part of any readiness signal. It only remembers your place in this ordered guide.
- Run /helpNot done
- Run /verify-triageNot done
- Run /clearNot done
- Run /compactNot done
- Run claude -p "Summarize this diff" --output-format jsonNot done
- Run claude -p "Summarize this diff" --output-format stream-json --verbose --include-partial-messagesNot done
- Run /simulate-hook-denialNot done
Assemble the instruction hierarchy
Assign every prepared fragment to a scope. Claude Code concatenates discovered instruction files from the filesystem root down to the working directory: managed policy, user, project, then local.
Composed result
Every selected contribution is shown in root-down load order.
managed policy
managed policy
user
~/.claude/CLAUDE.md
project
./CLAUDE.md
local
./subdirectory/CLAUDE.md
Conflicting instructions remain present
Context is not enforcement
Implemented set
These are the only invocations this simulator can show. Other input receives an explicit “not implemented here” result; it never invents a model response.
| Invocation | Kind | What this simulation shows | Source |
|---|---|---|---|
/help | built-in | The built-in help command shows help and the available commands. | Read the dated source |
/clear | built-in | Clear starts a new conversation with empty context. | Read the dated source |
/compact | built-in | Compact summarizes the conversation so far and continues the same conversation. | Read the dated source |
/verify-triage | Custom command | From .claude/commands/verify-triage.md at project scope. This project command is loaded from .claude/commands/verify-triage.md at repository scope.
| Read the dated source |
claude -p "Summarize this diff" --output-format json | mode | Print mode runs non-interactively, can read standard input, and exits zero on success or non-zero on failure. JSON output carries response text in the result field; --continue uses the most recent conversation and --resume <session-id> uses a specific conversation. | Read the dated source |
claude -p "Summarize this diff" --output-format stream-json --verbose --include-partial-messages | mode | Stream JSON emits one JSON event per line, beginning with system/init and ending with a result message. Streaming requires verbose and partial-message output. | Read the dated source |
/init | built-in | Init initializes a project with a CLAUDE.md guide. | Read the dated source |
/permissions | built-in | Permissions manages allow, ask, and deny rules by scope. | Read the dated source |
/model | built-in | Model switches the model and saves it as the default for new sessions. | Read the dated source |
/cost | built-in | Cost is an alias for the usage command. | Read the dated source |
/simulate-hook-denial | mode | This simulation shows a PreToolUse hook blocking a destructive tool action before it runs. | Read the dated source |
Reference components
These components count toward the module’s coverage, but they are reference material rather than commands. They are intentionally not offered as terminal input.
Rules
Where it lives:
CLAUDE.mdCLAUDE.md instructions are context that shapes behavior; they do not enforce actions. Read the dated source
Skills
Where it lives:
.claude/skills/A Skill is a loaded, prompt-based Markdown bundle that Claude uses with its tools. Read the dated source
Agents
Where it lives:
.claude/agents/A subagent works in a separate context window and returns a summary to the main conversation. Read the dated source
Agent Memory
Where it lives:
~/.claude/Auto memory is loaded as context alongside CLAUDE.md instructions. Read the dated source
auto-mode
Where it lives:
settings.jsonIn Auto mode a second model, the classifier, reviews actions instead of the user; in Manual mode Claude Code asks before most file edits, shell commands, and network actions. Read the dated source
`CLAUDE.md` hierarchy
Where it lives:
CLAUDE.mdInstruction scopes load as managed policy, user, project, and local; discovered files are concatenated from the filesystem root toward the working directory. Read the dated source
Repository worked example
This inventory is generated from the repository files at publication time. One representative file per teaching type is open for inspection; every discovered path remains listed.
Rules
1 file in the inventory
CLAUDE.mdRepository fileStudy note
Representative source: CLAUDE.md
# Project Claude Code instructions
This is the project-level Claude Code instruction file. Claude Code composes instructions from the
enterprise, user, project, and subdirectory levels; nearer subdirectory instructions refine the
project rules for their subtree. This file supplies the project-level configuration and does not
override enterprise or user policy.
Follow [AGENTS.md](AGENTS.md) for the repository's content, security, test, and commit rules. Read
[BLUEPRINT.md](BLUEPRINT.md) before changing study material. Keep lab tests keyless, use Python
3.11+ standard-library-first code, and run `ruff check .`, `ruff format --check .`, and `pytest -q`
after changes.
Claude Opus 5, acting as the orchestrator in Claude Code, may run `git add` and `git commit`, and
only after the full gate set passes. The permission is scoped to that model in that role: every
delegated implementer — Codex, Antigravity, or any other CLI — leaves its work uncommitted in the
working tree for the orchestrator to review, re-gate, and commit. [AGENTS.md](AGENTS.md) no longer
states the older blanket prohibition, so this paragraph is the only rule on the subject rather than
an override of a conflicting one.
Use `/verify-triage` to run the triage verification sequence. Use the `triage-security` skill when
reviewing the untrusted-input boundary, secret handling, or tool permissions.
<!-- SPECKIT START -->
The active feature is `004-item-bank-expansion`. For the technologies in use, the project structure,
and the shell commands that verify a change, read [the implementation
plan](specs/004-item-bank-expansion/plan.md) and [its
quickstart](specs/004-item-bank-expansion/quickstart.md). Feature 003's
[plan](specs/003-claude-code-domain/plan.md) describes the Claude Code module, feature 002's
[plan](specs/002-lab-runner-mock-exam/plan.md) describes the lab runner and the mock exam, and
feature 001's [plan](specs/001-study-site-foundation/plan.md) still describes the site's
foundation.
The site is an Astro 7 and TypeScript project in `site/`, rendering this repository's existing
markdown in place — copying study text into `site/` fails the build. Exam figures come from
`site/src/data/blueprint.json`, generated from `BLUEPRINT.md` by `tools/export_site_data.py`; never
edit that file or type a weight by hand. The same rule now covers `site/src/data/mock.json` and
`site/src/data/items.json`, generated by `tools/export_mock_data.py` and
`tools/export_item_bank.py`.
Pyodide runs `lab/` and `drills/` in a Web Worker on lab pages only, fetched after an explicit Run
and never before; the mock exam and the quizzes are plain TypeScript over build-time data and must
never import the runtime client. Per-domain quotas come from `drills.engine.mock.apportion_items` at
build time — never reimplement apportionment in TypeScript. Practice items live in `drills/bank/`
and must be original, validated by `python -m drills.engine validate`.
The Claude Code module adds `site/src/data/claude-code.json`, generated by
`tools/export_claude_code_data.py` from `claude-code/commands.yml`, this repository's own `.claude/`
directory, and a recording of what its hook actually decides — never hand-edit it, and never write a
sentence in `site/` describing what that hook denies. Only the configuration builder may reach the
runtime client, through a `run-hook` message whose exit code is a decision: a hook exiting `2` is
the hook working, not a failure. The instruction hierarchy is concatenated root-down, never
overridden, and terminal transcripts are never written to the candidate's device.
<!-- SPECKIT END -->
Settings
1 file in the inventory
.claude/settings.jsonRepository fileStudy note
Representative source: .claude/settings.json
{
"permissions": {
"allow": [
"Bash(ruff check .)",
"Bash(ruff format --check .)",
"Bash(pytest -q)",
"Bash(python -c:*)"
],
"deny": [
"Read(.env)",
"Read(.env.*)"
]
},
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "python \"$CLAUDE_PROJECT_DIR/.claude/hooks/prevent_destructive_actions.py\"",
"timeout": 5
}
]
},
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "python \"$CLAUDE_PROJECT_DIR/.claude/hooks/prevent_destructive_actions.py\"",
"timeout": 5
}
]
}
]
}
}
Command
1 file in the inventory
.claude/commands/verify-triage.mdRepository fileStudy note
Representative source: .claude/commands/verify-triage.md
---
description: Run the triage lab's keyless lint, format, and test gates
allowed-tools:
["Bash(ruff check .)", "Bash(ruff format --check .)", "Bash(pytest -q)"]
---
Run these commands from the repository root, in order:
1. `ruff check .`
2. `ruff format --check .`
3. `pytest -q`
Report each command's outcome. Do not change files while this command is running; use the normal
editing workflow to fix a failure, then invoke `/verify-triage` again.
Skill
15 files in the inventory
.claude/skills/speckit-analyze/SKILL.mdRepository fileStudy note.claude/skills/speckit-checklist/SKILL.mdRepository fileStudy note.claude/skills/speckit-clarify/SKILL.mdRepository fileStudy note.claude/skills/speckit-constitution/SKILL.mdRepository fileStudy note.claude/skills/speckit-git-commit/SKILL.mdRepository fileStudy note.claude/skills/speckit-git-feature/SKILL.mdRepository fileStudy note.claude/skills/speckit-git-initialize/SKILL.mdRepository fileStudy note.claude/skills/speckit-git-remote/SKILL.mdRepository fileStudy note.claude/skills/speckit-git-validate/SKILL.mdRepository fileStudy note.claude/skills/speckit-implement/SKILL.mdRepository fileStudy note.claude/skills/speckit-plan/SKILL.mdRepository fileStudy note.claude/skills/speckit-specify/SKILL.mdRepository fileStudy note.claude/skills/speckit-tasks/SKILL.mdRepository fileStudy note.claude/skills/speckit-taskstoissues/SKILL.mdRepository fileStudy note.claude/skills/triage-security/SKILL.mdRepository fileStudy note
Representative source: .claude/skills/triage-security/SKILL.md
---
name: triage-security
description: >-
Use when reviewing or changing triage untrusted-input boundaries, PII redaction, output leakage
checks, API-key handling, or tool exposure policy.
---
# Triage security review
Read `AGENTS.md`, `BLUEPRINT.md`, `lab/ingest.py`, `lab/security.py`, and `lab/secrets.py` before
making a security change. Preserve the four layers: input inspection is a recorded signal;
`lab.ingest` provides the nonce-bound JSON data boundary; `ToolExposurePolicy` is the capability
boundary; output checking prevents trusted-content leakage.
Do not treat pattern matching or approval as a substitute for least privilege. Untrusted tickets
must keep read-only tool exposure even when an approval decision is present. Redact PII before logs
or traces, resolve live credentials only from the environment, and never add a secret to fixtures,
prompts, exception text, or documentation.
Run `/verify-triage` after changes. For hook changes, also execute
`python .claude/hooks/prevent_destructive_actions.py` with representative `PreToolUse` JSON input.
Agent
1 file in the inventory
.claude/agents/triage-security-reviewer.mdRepository fileStudy note
Representative source: .claude/agents/triage-security-reviewer.md
---
name: triage-security-reviewer
description: >-
Use this agent to review a triage security change for untrusted-input boundaries, least-privilege
tool exposure, PII or secret leakage, and keyless test coverage.
model: inherit
color: red
tools: ["Read", "Grep", "Glob", "Bash"]
---
Review the change without editing files. Read `AGENTS.md` and `BLUEPRINT.md` first. Inspect the
request boundary in `lab/ingest.py`, the four security layers in `lab/security.py`, credential
handling in `lab/secrets.py`, and tool dispatch in `lab/tools/dispatcher.py`.
Report only concrete findings with file paths and concise evidence. Verify that untrusted ticket
text cannot forge the nonce-bound closing delimiter, write tools require both trusted capability
exposure and explicit approval, diagnostics redact PII and credentials, and tests remain keyless.
Run the requested test subset or the complete verification gates when useful.
Hook
1 file in the inventory
.claude/hooks/prevent_destructive_actions.pyRepository fileStudy note
Representative source: .claude/hooks/prevent_destructive_actions.py
#!/usr/bin/env python3
"""Deny protected-file writes and destructive shell commands from Claude Code PreToolUse hooks."""
from __future__ import annotations
import json
import re
import sys
from pathlib import PurePath
from typing import Any
PROTECTED_FILES = frozenset({"LICENSE"})
_DESTRUCTIVE_COMMAND = re.compile(
r"(?:\brm\s+-[a-z]*[rf]|\brmdir\s+/[sq]|\bdel\s+/[a-z]*[sqf]|"
r"\bremove-item\b.{0,80}\b-recurse\b|\bgit\s+reset\s+--hard\b|"
r"\bgit\s+clean\s+-[a-z]*f|\bformat\s+[a-z]:|\bmkfs\b|\bdd\s+if=)",
re.IGNORECASE,
)
def _deny(message: str) -> int:
"""Tell Claude Code that the PreToolUse action is denied, then return a failing status."""
print(
json.dumps(
{
"hookSpecificOutput": {"permissionDecision": "deny"},
"systemMessage": message,
}
),
file=sys.stderr,
)
return 2
def _protected_path(value: object) -> bool:
"""Match a protected basename from a relative or absolute write path."""
if not isinstance(value, str):
return False
return PurePath(value.replace("\\", "/")).name.upper() in PROTECTED_FILES
def _protected_file_in_command(command: str) -> str | None:
"""Return the protected filename referenced by a shell command, if any."""
for filename in PROTECTED_FILES:
if re.search(rf"(?<![A-Z0-9_]){re.escape(filename)}(?![A-Z0-9_])", command, re.IGNORECASE):
return filename
return None
def decide(payload: dict[str, Any]) -> int:
"""Return the hook status code for one Claude Code PreToolUse payload."""
tool_input = payload.get("tool_input", {})
if not isinstance(tool_input, dict):
return 0
file_path = tool_input.get("file_path")
if _protected_path(file_path):
return _deny(f"Protected ground-truth file write denied: {file_path}")
command = tool_input.get("command")
if not isinstance(command, str):
return 0
protected_file = _protected_file_in_command(command)
if protected_file is not None:
return _deny(f"Protected ground-truth file write denied: {protected_file}")
if _DESTRUCTIVE_COMMAND.search(command):
return _deny("Destructive shell command denied by the project safety hook.")
return 0
def main() -> int:
"""Parse JSON from standard input, allowing empty or malformed unrelated hook input to pass."""
try:
payload = json.load(sys.stdin)
except json.JSONDecodeError:
return 0
if not isinstance(payload, dict):
return 0
return decide(payload)
if __name__ == "__main__":
raise SystemExit(main())
Supporting inventory
Supporting and unrecognized files stay visible without being presented as teaching types.
Documentation
.claude/README.mdRepository fileStudy note
Recorded hook decisions
Each payload and result below was captured by executing .claude/hooks/prevent_destructive_actions.py at publication time. Decision details and output are rendered from that recording.
a write to a protected ground-truth file
- Decision
- deny
- Exit code
- 2
Payload
{
"tool_name": "Write",
"tool_input": {
"file_path": "LICENSE"
}
}Hook message
{"hookSpecificOutput": {"permissionDecision": "deny"}, "systemMessage": "Protected ground-truth file write denied: LICENSE"}
a write to an ordinary source file
- Decision
- allow
- Exit code
- 0
Payload
{
"tool_name": "Write",
"tool_input": {
"file_path": "lab/security.py"
}
}Hook message
a destructive shell command
- Decision
- deny
- Exit code
- 2
Payload
{
"tool_name": "Bash",
"tool_input": {
"command": "git reset --hard"
}
}Hook message
{"hookSpecificOutput": {"permissionDecision": "deny"}, "systemMessage": "Destructive shell command denied by the project safety hook."}
an ordinary shell command
- Decision
- allow
- Exit code
- 0
Payload
{
"tool_name": "Bash",
"tool_input": {
"command": "python -V"
}
}Hook message
a shell command that only mentions a protected filename
- Decision
- deny
- Exit code
- 2
Payload
{
"tool_name": "Bash",
"tool_input": {
"command": "echo LICENSE"
}
}Hook message
{"hookSpecificOutput": {"permissionDecision": "deny"}, "systemMessage": "Protected ground-truth file write denied: LICENSE"}
a malformed or empty payload
- Decision
- allow
- Exit code
- 0
Payload
[]Hook message