| name | scope |
| description | Use ClaudeScope to analyze FRC robot .wpilog files or query live NetworkTables. Invoke when the user asks to analyze a log file, query robot data, check field values, find time ranges, compute statistics, or investigate robot performance from telemetry. Trigger on: "analyze log", "load wpilog", "check NT", "query robot data", "/scope".
|
ClaudeScope — AI Agent Guide
ClaudeScope is a CLI tool that parses FRC .wpilog files and queries live NetworkTables. It runs a daemon on port 5812 (auto-starts on first use).
Setup
Download the binary for your platform from the GitHub Releases page and add it to PATH:
| Platform | Binary |
|---|
| Windows | ClaudeScope-windows-amd64.exe → rename to ClaudeScope.exe |
| macOS (Apple Silicon) | ClaudeScope-darwin-arm64 → rename to ClaudeScope |
| macOS (Intel) | ClaudeScope-darwin-amd64 → rename to ClaudeScope |
| Linux | ClaudeScope-linux-amd64 → rename to ClaudeScope |
Verify: ClaudeScope version
Workflow
1. Load the log (or connect to NT) → get session_id
2. Run queries (--session is optional with one session open)
3. Disconnect when done
Critical Notes
- Default session:
--session is optional when exactly one session is active — every command defaults to it, so you usually don't need to thread the ID through. With zero sessions you get a NO_SESSION error; with multiple, an AMBIGUOUS_SESSION error listing the IDs (pass --session <id> to pick one, or run sessions to see them).
- Git Bash path issue: Keys starting with
/ get mangled by MSYS2. Always prefix commands with MSYS_NO_PATHCONV=1.
- Timestamps are microseconds (µs) since log start.
- Negative start/end = offset from end of log.
-5000000 = last 5 seconds.
- end=0 means end of log. time=0 in
get means latest value.
Commands
Load a .wpilog file
MSYS_NO_PATHCONV=1 ClaudeScope load "C:/path/to/file.wpilog"
Returns: {"session_id":"<id>","fields":[{"key":"...","type":"double|boolean|string|..."},...]}
Connect to live NT
ClaudeScope connect 10.0.0.2
Returns: {"session_id":"<id>"}
Disconnect
ClaudeScope disconnect --session <id>
List active sessions
ClaudeScope sessions
Returns: {"sessions":[{"id":"<id>","type":"log|live","label":"<path-or-ip>","idle_seconds":<n>},...]}
Use this to recover a session ID if you lost it (e.g. after context compaction) instead of re-loading the log.
List fields and time range
ClaudeScope info --session <id>
Returns: {"fields":[...],"start":<µs>,"end":<µs>}
Search field names
ClaudeScope search-fields voltage --session <id>
Case-insensitive substring match over the same field list info returns — useful for finding the right key in a log with hundreds of NT keys instead of scrolling through the full info output. Returns: {"fields":[{"key":"...","type":"..."},...]}
Get value at timestamp (time=0 → latest)
MSYS_NO_PATHCONV=1 ClaudeScope get /RealOutputs/Superstructure/State --session <id> --time 1500000
Returns: {"/key":{"timestamp":<µs>,"value":<any>}}
Get time-series data for a range
MSYS_NO_PATHCONV=1 ClaudeScope range /RealOutputs/Drive/LeftVelocity --session <id> --start 1000000 --end 5000000
Returns: {"/key":[{"timestamp":<µs>,"value":<any>},...]}
Add --format csv or --format parquet (default JSON) to get pandas-ready long-format {key,timestamp,value} rows across one or more keys — the recommended way to pull raw series into Python. See Analyze in pandas below.
Find bool ranges (e.g. when robot was enabled)
MSYS_NO_PATHCONV=1 ClaudeScope find-bool /RealOutputs/Robot/Enabled true --session <id>
Returns: [{"start":<µs>,"end":<µs>},...]
Find threshold ranges (e.g. when voltage was low)
MSYS_NO_PATHCONV=1 ClaudeScope find-threshold /RealOutputs/PowerDistribution/Voltage --min 10.0 --max 11.5 --session <id>
--min and --max are each optional — supply just one for a one-sided test (at least one is required):
MSYS_NO_PATHCONV=1 ClaudeScope find-threshold /RealOutputs/PowerDistribution/Voltage --max 11.0 --session <id>
MSYS_NO_PATHCONV=1 ClaudeScope find-threshold /RealOutputs/PowerDistribution/Current --min 40.0 --session <id>
Returns: [{"start":<µs>,"end":<µs>},...]
Statistics for a numeric field
MSYS_NO_PATHCONV=1 ClaudeScope stats /RealOutputs/Drive/LeftVelocity --session <id> --start 0 --end 0
Returns: {"mean":<f>,"median":<f>,"min":<f>,"max":<f>,"q1":<f>,"q3":<f>,"avg_delta":<f/s>,"min_delta":<f/s>,"max_delta":<f/s>}
Analyze in pandas (cs → parquet → pandas)
For anything beyond the single-field verbs above — correlating multiple fields, computed columns, filtering, resampling, per-group stats — pull the raw series with range --format parquet and do the transform in pandas, which handles nulls and formatting correctly for free.
MSYS_NO_PATHCONV=1 ClaudeScope range CurrentA CurrentB BatteryVoltage --session <id> --format parquet --out series.parquet
import pandas as pd
df = pd.read_parquet("series.parquet")
wide = df.pivot(index="timestamp", columns="key", values="value").ffill()
both_high = wide[(wide["CurrentA"] > 40) & (wide["CurrentB"] > 40)]
per_bucket = wide["CurrentA"].groupby(wide.index // 500_000).mean()
--format parquet preserves native bool/float64/string types and true nulls; --format csv stringifies everything (booleans as True/False so pandas.read_csv still infers bool dtype). Prefer Parquet for large results. If you're working in Python, prefer the Python client below — session.range_df(..., pivot=True) builds the DataFrame directly and skips the file round-trip.
WPILib struct fields (struct:Pose2d, struct:ChassisSpeeds, struct:SwerveModuleState[], Rotation2d/3d, Translation2d/3d, Pose3d, Transform2d/3d, Twist2d/3d, SwerveModulePosition, Quaternion) decode automatically to named-field objects (e.g. {"x":..,"y":..,"theta":..}) in get/range.
Set NT value (live sessions only)
MSYS_NO_PATHCONV=1 ClaudeScope set /SmartDashboard/SetSpeed=2.5 --session <id>
SendableChooser warning: Do NOT set <prefix>/active — the robot re-publishes that field every loop and will immediately overwrite your value. To change a chooser selection, write to <prefix>/selected:
MSYS_NO_PATHCONV=1 ClaudeScope set "/SmartDashboard/Auto Choices/selected=Depot" --session <id>
ClaudeScope will return an error if you try to set /active on a String Chooser topic, telling you the correct key to use.
Full machine-readable schema
ClaudeScope help
Python client (claudescope-py)
If the task is "pull telemetry and analyze it in pandas" in Python, prefer the claudescope package (ClaudeScope/python/) over shelling out to the CLI and parsing --format csv/--format parquet output yourself — it wraps the same CLI binary and returns a pandas.DataFrame directly:
import claudescope as scope
with scope.load("/path/to/log.wpilog") as session:
df = session.range_df("CurrentA", "CurrentB", pivot=True)
Covers load/connect/sessions/disconnect, range_df (→ tidy/pivoted DataFrame via Parquet), and get/range/find_bool/find_threshold/stats/set. Requires the ClaudeScope binary on PATH (or CLAUDESCOPE_BIN set). Failures raise claudescope.ClaudeScopeError with .code, not a raw subprocess error. See ClaudeScope/python/README.md for the full API and design notes.
Common Analysis Patterns
Superstructure state time analysis
MSYS_NO_PATHCONV=1 ClaudeScope range /RealOutputs/Superstructure/CurrentSuperState --session <id> --start 0 --end 0
Swerve tracking error
MSYS_NO_PATHCONV=1 ClaudeScope range /RealOutputs/Drive/Module0/TurnSetpointRads --session <id>
MSYS_NO_PATHCONV=1 ClaudeScope range /RealOutputs/Drive/Module0/TurnPositionRads --session <id>
Find match periods
MSYS_NO_PATHCONV=1 ClaudeScope find-bool /RealOutputs/Robot/DSAttached true --session <id>
AdvantageKit Log Notes
- Fields follow the pattern
/RealOutputs/<Subsystem>/<Field> and /RobotState/<Field>
- Struct fields (e.g.
SwerveModuleState) are logged as structschema type (raw bytes); decode manually
- Use
info to discover all field names before querying
- String fields hold enum values (e.g. superstructure states like
"IDLE", "SHOOTING")