aimx 0.3.0__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aimx-0.3.2/.agents/skills/aimx/SKILL.md +123 -0
- aimx-0.3.2/.agents/skills/aimx/agents/openai.yaml +4 -0
- aimx-0.3.2/.agents/skills/aimx/references/aimx-cli.md +233 -0
- aimx-0.3.2/.agents/skills/aimx/scripts/collect_experiment_snapshot.py +217 -0
- {aimx-0.3.0 → aimx-0.3.2}/.gitignore +9 -1
- {aimx-0.3.0 → aimx-0.3.2}/AGENTS.md +4 -0
- aimx-0.3.2/PKG-INFO +309 -0
- aimx-0.3.2/README.md +297 -0
- aimx-0.3.2/TODO.md +3 -0
- {aimx-0.3.0 → aimx-0.3.2}/pyproject.toml +2 -1
- aimx-0.3.2/specs/003-query-images-terminal-render/checklists/requirements.md +35 -0
- aimx-0.3.2/specs/003-query-images-terminal-render/contracts/cli-output.md +122 -0
- aimx-0.3.2/specs/003-query-images-terminal-render/data-model.md +112 -0
- aimx-0.3.2/specs/003-query-images-terminal-render/plan.md +166 -0
- aimx-0.3.2/specs/003-query-images-terminal-render/quickstart.md +98 -0
- aimx-0.3.2/specs/003-query-images-terminal-render/research.md +138 -0
- aimx-0.3.2/specs/003-query-images-terminal-render/spec.md +119 -0
- aimx-0.3.2/specs/003-query-images-terminal-render/tasks.md +250 -0
- aimx-0.3.2/specs/004-run-params-query/checklists/requirements.md +42 -0
- aimx-0.3.2/specs/004-run-params-query/contracts/cli-output.md +107 -0
- aimx-0.3.2/specs/004-run-params-query/data-model.md +121 -0
- aimx-0.3.2/specs/004-run-params-query/plan.md +175 -0
- aimx-0.3.2/specs/004-run-params-query/quickstart.md +112 -0
- aimx-0.3.2/specs/004-run-params-query/research.md +127 -0
- aimx-0.3.2/specs/004-run-params-query/spec.md +206 -0
- aimx-0.3.2/specs/004-run-params-query/tasks.md +241 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/__init__.py +1 -1
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/aim_bridge/metric_stats.py +201 -1
- aimx-0.3.2/src/aimx/aim_bridge/run_params.py +106 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/commands/help.py +9 -3
- aimx-0.3.2/src/aimx/commands/query.py +423 -0
- aimx-0.3.2/src/aimx/rendering/image_render.py +269 -0
- aimx-0.3.2/src/aimx/rendering/params_views.py +160 -0
- aimx-0.3.2/static/images.png +0 -0
- aimx-0.3.2/static/params.png +0 -0
- aimx-0.3.2/tests/contract/test_query_contract.py +446 -0
- aimx-0.3.2/tests/integration/test_query_command.py +521 -0
- {aimx-0.3.0 → aimx-0.3.2}/tests/integration/test_short_hash_and_steps.py +105 -3
- aimx-0.3.2/tests/unit/test_image_render.py +309 -0
- aimx-0.3.2/tests/unit/test_query_helpers.py +468 -0
- aimx-0.3.2/tests/unit/test_run_params.py +91 -0
- {aimx-0.3.0 → aimx-0.3.2}/uv.lock +16 -1
- aimx-0.3.0/.agents/skills/speckit-analyze/SKILL.md +0 -255
- aimx-0.3.0/.agents/skills/speckit-checklist/SKILL.md +0 -367
- aimx-0.3.0/.agents/skills/speckit-clarify/SKILL.md +0 -249
- aimx-0.3.0/.agents/skills/speckit-constitution/SKILL.md +0 -152
- aimx-0.3.0/.agents/skills/speckit-git-commit/SKILL.md +0 -53
- aimx-0.3.0/.agents/skills/speckit-git-feature/SKILL.md +0 -72
- aimx-0.3.0/.agents/skills/speckit-git-initialize/SKILL.md +0 -54
- aimx-0.3.0/.agents/skills/speckit-git-remote/SKILL.md +0 -50
- aimx-0.3.0/.agents/skills/speckit-git-validate/SKILL.md +0 -54
- aimx-0.3.0/.agents/skills/speckit-implement/SKILL.md +0 -204
- aimx-0.3.0/.agents/skills/speckit-plan/SKILL.md +0 -151
- aimx-0.3.0/.agents/skills/speckit-specify/SKILL.md +0 -325
- aimx-0.3.0/.agents/skills/speckit-tasks/SKILL.md +0 -197
- aimx-0.3.0/.agents/skills/speckit-taskstoissues/SKILL.md +0 -101
- aimx-0.3.0/PKG-INFO +0 -182
- aimx-0.3.0/README.md +0 -171
- aimx-0.3.0/src/aimx/commands/query.py +0 -191
- aimx-0.3.0/tests/contract/test_query_contract.py +0 -108
- aimx-0.3.0/tests/integration/test_query_command.py +0 -139
- aimx-0.3.0/tests/unit/test_query_helpers.py +0 -115
- {aimx-0.3.0 → aimx-0.3.2}/.codex/hooks.json +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/.github/workflows/CI.yaml +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/.github/workflows/publish.yaml +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/.python-version +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/CLAUDE.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/CONSTITUTION.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/LICENSE +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/specs/001-aim-command-passthrough/checklists/requirements.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/specs/001-aim-command-passthrough/contracts/cli-contract.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/specs/001-aim-command-passthrough/data-model.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/specs/001-aim-command-passthrough/plan.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/specs/001-aim-command-passthrough/quickstart.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/specs/001-aim-command-passthrough/research.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/specs/001-aim-command-passthrough/spec.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/specs/001-aim-command-passthrough/tasks.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/specs/002-aim-query-command/checklists/requirements.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/specs/002-aim-query-command/contracts/query-command.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/specs/002-aim-query-command/data-model.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/specs/002-aim-query-command/plan.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/specs/002-aim-query-command/quickstart.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/specs/002-aim-query-command/research.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/specs/002-aim-query-command/spec.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/specs/002-aim-query-command/tasks.md +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/__main__.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/aim_bridge/__init__.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/aim_bridge/hash_resolver.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/cli.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/commands/__init__.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/commands/doctor.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/commands/trace.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/commands/version.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/native_aim/__init__.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/native_aim/locator.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/native_aim/passthrough.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/rendering/__init__.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/rendering/colors.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/rendering/query_views.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/rendering/trace_views.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/src/aimx/router.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/static/metrics.png +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/static/trace.png +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/tests/conftest.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/tests/contract/test_cli_contract.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/tests/contract/test_trace_contract.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/tests/integration/conftest.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/tests/integration/test_missing_native_aim.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/tests/integration/test_missing_python_aim_package.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/tests/integration/test_passthrough_behavior.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/tests/integration/test_trace_command.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/tests/unit/test_hash_resolver.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/tests/unit/test_locator.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/tests/unit/test_metric_stats.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/tests/unit/test_owned_commands.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/tests/unit/test_router.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/tests/unit/test_step_filter.py +0 -0
- {aimx-0.3.0 → aimx-0.3.2}/tests/unit/test_trace_helpers.py +0 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: aimx
|
|
3
|
+
description: Use when autoresearch, log_experiment, experiment analysis, or automatic iteration workflows need to inspect local Aim repositories with aimx, collect run params, metric summaries, traces, image evidence, compare training runs, or summarize model results without mutating Aim data.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Aimx
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Use `aimx` as a read-only evidence collector for `autoresearch` `log_experiment`
|
|
11
|
+
steps. Prefer JSON output so downstream agents can compare runs, explain model
|
|
12
|
+
effects, and propose the next experiment from concrete Aim data.
|
|
13
|
+
|
|
14
|
+
## Requirements
|
|
15
|
+
|
|
16
|
+
- Require `aimx` in the Python environment that runs `log_experiment`.
|
|
17
|
+
Verify with `aimx --help` or `python -m aimx --help` before collecting data.
|
|
18
|
+
- When `aimx` is missing, first identify and follow the user's current
|
|
19
|
+
dependency-management workflow from project files and instructions
|
|
20
|
+
(`pyproject.toml`, lockfiles, README, AGENTS/CLAUDE/GEMINI notes, CI config).
|
|
21
|
+
Use that manager to add or install `aimx`. In this repository, prefer
|
|
22
|
+
`uv sync`, `uv run ...`, and `uv add aimx` because repo policy requires `uv`.
|
|
23
|
+
- If there is no project environment to modify and the user only needs a
|
|
24
|
+
standalone CLI, install `aimx` as a tool using the user's preferred tool
|
|
25
|
+
manager. Use `uv tool install aimx` only when `uv` is already the chosen or
|
|
26
|
+
accepted tool workflow.
|
|
27
|
+
- Require read access to a local Aim repository path. Pass `--repo` explicitly
|
|
28
|
+
and keep collection commands read-only.
|
|
29
|
+
- If native Aim availability matters for passthrough checks, run `aimx doctor`;
|
|
30
|
+
do not initialize, repair, migrate, or rewrite Aim repositories from this
|
|
31
|
+
skill.
|
|
32
|
+
|
|
33
|
+
## Workflow
|
|
34
|
+
|
|
35
|
+
1. Locate the Aim repository. Pass `--repo <repo-root-or-.aim>` explicitly; in
|
|
36
|
+
this repository, use `--repo data` or `--repo data/.aim` for local checks.
|
|
37
|
+
2. Define the run scope as an AimQL expression. Start broad with
|
|
38
|
+
`run.hash != ''`, then narrow by `run.hash`, `run.experiment`, or `run.name`.
|
|
39
|
+
3. Collect run parameters:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
aimx query params "<run-scope>" --repo <repo> --json
|
|
43
|
+
aimx query params "<run-scope>" --repo <repo> --json --param hparam.lr --param model
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
4. Collect metric summaries for candidate objective metrics:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
aimx query metrics "(<run-scope>) and metric.name == 'loss'" --repo <repo> --json
|
|
50
|
+
aimx query metrics "(<run-scope>) and metric.name != ''" --repo <repo> --json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
5. Collect traces only for decisive metrics or suspected anomalies:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
aimx trace "(<run-scope>) and metric.name == 'loss'" --repo <repo> --json --tail 50
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
6. Collect image metadata when qualitative outputs matter:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
aimx query images "images" --repo <repo> --json --head 20
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
7. Emit a compact `log_experiment` record containing:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"repo": "<repo>",
|
|
70
|
+
"run_scope": "<AimQL>",
|
|
71
|
+
"params": {},
|
|
72
|
+
"metric_summary": {},
|
|
73
|
+
"trace_evidence": {},
|
|
74
|
+
"image_evidence": {},
|
|
75
|
+
"interpretation": {
|
|
76
|
+
"best_runs": [],
|
|
77
|
+
"regressions": [],
|
|
78
|
+
"confidence": "low|medium|high",
|
|
79
|
+
"next_experiments": []
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Interpretation Rules
|
|
85
|
+
|
|
86
|
+
- Prefer validation, test, or held-out contexts over training contexts when
|
|
87
|
+
ranking runs.
|
|
88
|
+
- Treat `aimx query metrics` as summary data: `last`, `min`, `max`, and step
|
|
89
|
+
counts. Use `aimx trace --json` when shape, stability, divergence, or late
|
|
90
|
+
improvement matters.
|
|
91
|
+
- For minimization metrics such as loss or error, compare `min.value` and the
|
|
92
|
+
corresponding step. For maximization metrics such as accuracy, F1, AUC, or
|
|
93
|
+
IoU, compare `max.value`.
|
|
94
|
+
- Separate incomplete or failed runs from strong results before drawing
|
|
95
|
+
conclusions. Very low step counts, missing params, or missing validation
|
|
96
|
+
metrics should reduce confidence.
|
|
97
|
+
- Preserve read-only behavior. Do not run commands that initialize, repair,
|
|
98
|
+
migrate, delete, or rewrite Aim repositories during `log_experiment`.
|
|
99
|
+
|
|
100
|
+
## Helper Script
|
|
101
|
+
|
|
102
|
+
Use `scripts/collect_experiment_snapshot.py` when an agent needs one structured
|
|
103
|
+
JSON bundle instead of several manual commands.
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
uv run python skills/aimx/scripts/collect_experiment_snapshot.py \
|
|
107
|
+
--repo data \
|
|
108
|
+
--base-expr "run.experiment == 'cloud-segmentation'" \
|
|
109
|
+
--metric loss \
|
|
110
|
+
--trace-metric loss \
|
|
111
|
+
--param hparam.lr \
|
|
112
|
+
--param model \
|
|
113
|
+
--pretty
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The script uses the current Python interpreter as `python -m aimx` by default.
|
|
117
|
+
Pass `--aimx "aimx"` or `--aimx "uv run aimx"` when a different launcher is
|
|
118
|
+
needed. It writes only to stdout.
|
|
119
|
+
|
|
120
|
+
## Reference
|
|
121
|
+
|
|
122
|
+
Read `references/aimx-cli.md` for command details, JSON envelope shapes, and
|
|
123
|
+
suggested `log_experiment` evidence fields.
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# aimx CLI Reference for log_experiment
|
|
2
|
+
|
|
3
|
+
Use this reference when building an `autoresearch` `log_experiment` step from a
|
|
4
|
+
local Aim repository. All commands below are read-only inspection commands.
|
|
5
|
+
|
|
6
|
+
## Installation Requirement
|
|
7
|
+
|
|
8
|
+
`aimx` must be installed in the environment that runs the collection commands.
|
|
9
|
+
Verify one of these before collecting:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
aimx --help
|
|
13
|
+
python -m aimx --help
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
If it is missing, inspect the current project first and use the dependency
|
|
17
|
+
manager it already uses. Check project instructions, `pyproject.toml`, lockfiles,
|
|
18
|
+
README setup docs, and CI config before choosing a command.
|
|
19
|
+
|
|
20
|
+
Examples:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# uv-managed project
|
|
24
|
+
uv add aimx
|
|
25
|
+
uv sync
|
|
26
|
+
|
|
27
|
+
# Poetry-managed project
|
|
28
|
+
poetry add aimx
|
|
29
|
+
|
|
30
|
+
# Pipenv-managed project
|
|
31
|
+
pipenv install aimx
|
|
32
|
+
|
|
33
|
+
# requirements.txt project
|
|
34
|
+
python -m pip install aimx
|
|
35
|
+
python -m pip freeze > requirements.txt
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Use the project's normal lockfile/update flow. For this `aimx` repository,
|
|
39
|
+
prefer `uv sync`, `uv run ...`, and `uv add aimx` because repo policy requires
|
|
40
|
+
`uv`. For a standalone CLI with no project dependency to modify, use the user's
|
|
41
|
+
preferred tool manager; use `uv tool install aimx` only when `uv` is already the
|
|
42
|
+
chosen or accepted workflow.
|
|
43
|
+
|
|
44
|
+
## Repository Paths
|
|
45
|
+
|
|
46
|
+
`--repo` accepts either the Aim repository root or the `.aim` metadata
|
|
47
|
+
directory. Prefer explicit repo paths so automation does not accidentally read a
|
|
48
|
+
user-level or unrelated Aim repository.
|
|
49
|
+
|
|
50
|
+
Examples:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
aimx query params "run.hash != ''" --repo data --json
|
|
54
|
+
aimx query params "run.hash != ''" --repo data/.aim --json
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## AimQL Scoping
|
|
58
|
+
|
|
59
|
+
Use AimQL in the expression argument. Common run scopes:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
run.hash != ''
|
|
63
|
+
run.hash == 'eca37394'
|
|
64
|
+
run.experiment == 'cloud-segmentation'
|
|
65
|
+
run.name == 'resnet-ft-0420'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Metric expressions combine run fields with metric fields:
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
(run.experiment == 'cloud-segmentation') and metric.name == 'loss'
|
|
72
|
+
(run.hash == 'eca37394') and metric.name != ''
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Short run hashes are expanded by `aimx` where supported.
|
|
76
|
+
|
|
77
|
+
## Params
|
|
78
|
+
|
|
79
|
+
Use params first to understand the design of each run.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
aimx query params "<run-scope>" --repo <repo> --json
|
|
83
|
+
aimx query params "<run-scope>" --repo <repo> --json --param hparam.lr --param model
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
JSON shape:
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"target": "params",
|
|
91
|
+
"repo": "data",
|
|
92
|
+
"expression": "run.hash != ''",
|
|
93
|
+
"runs_count": 2,
|
|
94
|
+
"param_keys": ["hparam.lr", "model"],
|
|
95
|
+
"runs": [
|
|
96
|
+
{
|
|
97
|
+
"hash": "full-run-hash",
|
|
98
|
+
"experiment": "experiment-name",
|
|
99
|
+
"name": "run-name",
|
|
100
|
+
"params": {"hparam.lr": 0.0001, "model": "ResNet"},
|
|
101
|
+
"missing_params": []
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Use `missing_params` as a confidence signal when comparing runs.
|
|
108
|
+
|
|
109
|
+
## Metric Summaries
|
|
110
|
+
|
|
111
|
+
Use metric summaries to rank runs cheaply.
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
aimx query metrics "<metric-expr>" --repo <repo> --json
|
|
115
|
+
aimx query metrics "<metric-expr>" --repo <repo> --json --steps 100:500
|
|
116
|
+
aimx query metrics "<metric-expr>" --repo <repo> --json --epochs 1:10
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
JSON shape:
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"target": "metrics",
|
|
124
|
+
"repo": "data",
|
|
125
|
+
"expression": "metric.name == 'loss'",
|
|
126
|
+
"runs_count": 1,
|
|
127
|
+
"metrics_count": 2,
|
|
128
|
+
"runs": [
|
|
129
|
+
{
|
|
130
|
+
"hash": "full-run-hash",
|
|
131
|
+
"experiment": "experiment-name",
|
|
132
|
+
"name": "run-name",
|
|
133
|
+
"metrics": [
|
|
134
|
+
{
|
|
135
|
+
"name": "loss",
|
|
136
|
+
"context": {"subset": "val"},
|
|
137
|
+
"steps": 110,
|
|
138
|
+
"last": {"value": 0.43, "step": 110},
|
|
139
|
+
"min": {"value": 0.32, "step": 60},
|
|
140
|
+
"max": {"value": 0.48, "step": 107}
|
|
141
|
+
}
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Use `context` to distinguish train, val, test, dataset split, seed, or other
|
|
149
|
+
metric dimensions.
|
|
150
|
+
|
|
151
|
+
## Traces
|
|
152
|
+
|
|
153
|
+
Use traces when a summary hides important behavior such as late overfitting,
|
|
154
|
+
instability, divergence, or plateauing.
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
aimx trace "<metric-expr>" --repo <repo> --json
|
|
158
|
+
aimx trace "<metric-expr>" --repo <repo> --json --tail 50
|
|
159
|
+
aimx trace "<metric-expr>" --repo <repo> --json --steps 100:500 --every 5
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
JSON shape:
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
[
|
|
166
|
+
{
|
|
167
|
+
"run": {
|
|
168
|
+
"hash": "full-run-hash",
|
|
169
|
+
"experiment": "experiment-name",
|
|
170
|
+
"name": "run-name"
|
|
171
|
+
},
|
|
172
|
+
"metric": "loss",
|
|
173
|
+
"context": {"subset": "val"},
|
|
174
|
+
"count": 50,
|
|
175
|
+
"steps": [1, 2, 3],
|
|
176
|
+
"epochs": [1.0, 2.0, 3.0],
|
|
177
|
+
"values": [0.9, 0.7, 0.5]
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
If no metrics match, current `aimx trace --json` may print a text message
|
|
183
|
+
instead of JSON. Treat that as no trace evidence rather than a parsing failure.
|
|
184
|
+
|
|
185
|
+
## Images
|
|
186
|
+
|
|
187
|
+
Use images for qualitative checks such as sample predictions, masks, generated
|
|
188
|
+
outputs, confusion examples, or visual regressions.
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
aimx query images "images" --repo <repo> --json
|
|
192
|
+
aimx query images "images" --repo <repo> --json --head 20
|
|
193
|
+
aimx query images "images" --repo <repo> --json --epochs 10:50
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
JSON shape:
|
|
197
|
+
|
|
198
|
+
```json
|
|
199
|
+
{
|
|
200
|
+
"target": "images",
|
|
201
|
+
"repo": "data",
|
|
202
|
+
"expression": "images",
|
|
203
|
+
"count": 1,
|
|
204
|
+
"rows": [
|
|
205
|
+
{
|
|
206
|
+
"run_hash": "full-run-hash",
|
|
207
|
+
"experiment": "experiment-name",
|
|
208
|
+
"name": "example",
|
|
209
|
+
"context": {"epoch": 10, "subset": "val"}
|
|
210
|
+
}
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Use image metadata in automated logs; render images manually only when the user
|
|
216
|
+
asks for visual inspection.
|
|
217
|
+
|
|
218
|
+
## log_experiment Evidence Fields
|
|
219
|
+
|
|
220
|
+
Recommended fields for autoresearch output:
|
|
221
|
+
|
|
222
|
+
- `run_scope`: AimQL expression and repo path used for evidence.
|
|
223
|
+
- `params`: selected hyperparameters and model identifiers per run.
|
|
224
|
+
- `metric_summary`: objective metric summaries per run and context.
|
|
225
|
+
- `trace_evidence`: sampled value arrays for decisive metrics.
|
|
226
|
+
- `image_evidence`: image row counts and representative contexts.
|
|
227
|
+
- `ranking`: best run per objective, objective direction, and tie-breakers.
|
|
228
|
+
- `regressions`: runs worse than baseline, incomplete runs, missing metrics, or
|
|
229
|
+
suspicious curves.
|
|
230
|
+
- `next_experiments`: concrete parameter changes grounded in the evidence.
|
|
231
|
+
|
|
232
|
+
Keep conclusions tied to the collected data. When metric direction is unknown,
|
|
233
|
+
state the assumption before ranking.
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Collect a read-only aimx experiment snapshot for autoresearch logs."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import json
|
|
8
|
+
import shlex
|
|
9
|
+
import subprocess
|
|
10
|
+
import sys
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class CommandPayload:
|
|
17
|
+
argv: list[str]
|
|
18
|
+
ok: bool
|
|
19
|
+
data: Any | None = None
|
|
20
|
+
message: str | None = None
|
|
21
|
+
error: str | None = None
|
|
22
|
+
|
|
23
|
+
def as_dict(self) -> dict[str, Any]:
|
|
24
|
+
payload: dict[str, Any] = {"argv": self.argv, "ok": self.ok}
|
|
25
|
+
if self.data is not None:
|
|
26
|
+
payload["data"] = self.data
|
|
27
|
+
if self.message:
|
|
28
|
+
payload["message"] = self.message
|
|
29
|
+
if self.error:
|
|
30
|
+
payload["error"] = self.error
|
|
31
|
+
return payload
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def parse_args() -> argparse.Namespace:
|
|
35
|
+
parser = argparse.ArgumentParser(
|
|
36
|
+
description="Collect params, metric summaries, optional traces, and image metadata with aimx."
|
|
37
|
+
)
|
|
38
|
+
parser.add_argument("--repo", default=".", help="Aim repo root or .aim metadata path.")
|
|
39
|
+
parser.add_argument(
|
|
40
|
+
"--base-expr",
|
|
41
|
+
default="run.hash != ''",
|
|
42
|
+
help="AimQL run scope used for params and generated metric expressions.",
|
|
43
|
+
)
|
|
44
|
+
parser.add_argument(
|
|
45
|
+
"--metric",
|
|
46
|
+
action="append",
|
|
47
|
+
default=[],
|
|
48
|
+
help="Metric name to summarize; repeatable. Defaults to all metrics when no metric expression is supplied.",
|
|
49
|
+
)
|
|
50
|
+
parser.add_argument(
|
|
51
|
+
"--metric-expr",
|
|
52
|
+
action="append",
|
|
53
|
+
default=[],
|
|
54
|
+
help="Full AimQL metric expression to summarize; repeatable.",
|
|
55
|
+
)
|
|
56
|
+
parser.add_argument(
|
|
57
|
+
"--trace-metric",
|
|
58
|
+
action="append",
|
|
59
|
+
default=[],
|
|
60
|
+
help="Metric name to collect trace samples for; repeatable.",
|
|
61
|
+
)
|
|
62
|
+
parser.add_argument(
|
|
63
|
+
"--trace-expr",
|
|
64
|
+
action="append",
|
|
65
|
+
default=[],
|
|
66
|
+
help="Full AimQL trace expression; repeatable.",
|
|
67
|
+
)
|
|
68
|
+
parser.add_argument(
|
|
69
|
+
"--trace-tail",
|
|
70
|
+
type=int,
|
|
71
|
+
default=50,
|
|
72
|
+
help="Tail sample count for trace commands. Use 0 to disable tail sampling.",
|
|
73
|
+
)
|
|
74
|
+
parser.add_argument(
|
|
75
|
+
"--param",
|
|
76
|
+
action="append",
|
|
77
|
+
default=[],
|
|
78
|
+
help="Parameter key to select; repeatable. Omit to let aimx discover params.",
|
|
79
|
+
)
|
|
80
|
+
parser.add_argument(
|
|
81
|
+
"--include-images",
|
|
82
|
+
action="store_true",
|
|
83
|
+
help="Also collect image metadata with aimx query images.",
|
|
84
|
+
)
|
|
85
|
+
parser.add_argument(
|
|
86
|
+
"--image-expr",
|
|
87
|
+
default="images",
|
|
88
|
+
help="AimQL image expression used when --include-images is set.",
|
|
89
|
+
)
|
|
90
|
+
parser.add_argument(
|
|
91
|
+
"--image-head",
|
|
92
|
+
type=int,
|
|
93
|
+
default=20,
|
|
94
|
+
help="Limit image metadata rows when --include-images is set.",
|
|
95
|
+
)
|
|
96
|
+
parser.add_argument(
|
|
97
|
+
"--aimx",
|
|
98
|
+
default=f"{sys.executable} -m aimx",
|
|
99
|
+
help='Launcher for aimx, for example "aimx", "uv run aimx", or "python -m aimx".',
|
|
100
|
+
)
|
|
101
|
+
parser.add_argument("--timeout", type=int, default=60, help="Per-command timeout in seconds.")
|
|
102
|
+
parser.add_argument("--pretty", action="store_true", help="Pretty-print JSON output.")
|
|
103
|
+
return parser.parse_args()
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def aimql_string(value: str) -> str:
|
|
107
|
+
return "'" + value.replace("\\", "\\\\").replace("'", "\\'") + "'"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def metric_expression(base_expr: str, metric_name: str) -> str:
|
|
111
|
+
return f"({base_expr}) and metric.name == {aimql_string(metric_name)}"
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def run_json(base_cmd: list[str], args: list[str], timeout: int) -> CommandPayload:
|
|
115
|
+
argv = [*base_cmd, *args]
|
|
116
|
+
try:
|
|
117
|
+
completed = subprocess.run(
|
|
118
|
+
argv,
|
|
119
|
+
check=False,
|
|
120
|
+
capture_output=True,
|
|
121
|
+
text=True,
|
|
122
|
+
timeout=timeout,
|
|
123
|
+
)
|
|
124
|
+
except FileNotFoundError as exc:
|
|
125
|
+
return CommandPayload(argv=argv, ok=False, error=str(exc))
|
|
126
|
+
except subprocess.TimeoutExpired as exc:
|
|
127
|
+
return CommandPayload(argv=argv, ok=False, error=f"Timed out after {timeout}s: {exc}")
|
|
128
|
+
|
|
129
|
+
stdout = completed.stdout.strip()
|
|
130
|
+
stderr = completed.stderr.strip()
|
|
131
|
+
if completed.returncode != 0:
|
|
132
|
+
return CommandPayload(
|
|
133
|
+
argv=argv,
|
|
134
|
+
ok=False,
|
|
135
|
+
message=stdout or None,
|
|
136
|
+
error=stderr or f"Command exited with status {completed.returncode}",
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
if not stdout:
|
|
140
|
+
return CommandPayload(argv=argv, ok=True, data=None)
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
return CommandPayload(argv=argv, ok=True, data=json.loads(stdout))
|
|
144
|
+
except json.JSONDecodeError:
|
|
145
|
+
return CommandPayload(argv=argv, ok=True, message=stdout)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def collect_snapshot(args: argparse.Namespace) -> tuple[dict[str, Any], bool]:
|
|
149
|
+
base_cmd = shlex.split(args.aimx)
|
|
150
|
+
metric_exprs = list(args.metric_expr)
|
|
151
|
+
metric_exprs.extend(metric_expression(args.base_expr, name) for name in args.metric)
|
|
152
|
+
if not metric_exprs:
|
|
153
|
+
metric_exprs.append(f"({args.base_expr}) and metric.name != ''")
|
|
154
|
+
|
|
155
|
+
trace_exprs = list(args.trace_expr)
|
|
156
|
+
trace_exprs.extend(metric_expression(args.base_expr, name) for name in args.trace_metric)
|
|
157
|
+
|
|
158
|
+
params_args = ["query", "params", args.base_expr, "--repo", args.repo, "--json"]
|
|
159
|
+
for key in args.param:
|
|
160
|
+
params_args.extend(["--param", key])
|
|
161
|
+
|
|
162
|
+
params = run_json(base_cmd, params_args, args.timeout)
|
|
163
|
+
|
|
164
|
+
metrics = [
|
|
165
|
+
run_json(base_cmd, ["query", "metrics", expr, "--repo", args.repo, "--json"], args.timeout)
|
|
166
|
+
for expr in metric_exprs
|
|
167
|
+
]
|
|
168
|
+
|
|
169
|
+
trace_common = ["--repo", args.repo, "--json"]
|
|
170
|
+
if args.trace_tail > 0:
|
|
171
|
+
trace_common.extend(["--tail", str(args.trace_tail)])
|
|
172
|
+
traces = [
|
|
173
|
+
run_json(base_cmd, ["trace", expr, *trace_common], args.timeout)
|
|
174
|
+
for expr in trace_exprs
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
images = None
|
|
178
|
+
if args.include_images:
|
|
179
|
+
image_args = [
|
|
180
|
+
"query",
|
|
181
|
+
"images",
|
|
182
|
+
args.image_expr,
|
|
183
|
+
"--repo",
|
|
184
|
+
args.repo,
|
|
185
|
+
"--json",
|
|
186
|
+
"--head",
|
|
187
|
+
str(args.image_head),
|
|
188
|
+
]
|
|
189
|
+
images = run_json(base_cmd, image_args, args.timeout)
|
|
190
|
+
|
|
191
|
+
snapshot: dict[str, Any] = {
|
|
192
|
+
"repo": args.repo,
|
|
193
|
+
"base_expr": args.base_expr,
|
|
194
|
+
"read_only": True,
|
|
195
|
+
"params": params.as_dict(),
|
|
196
|
+
"metrics": [item.as_dict() for item in metrics],
|
|
197
|
+
"traces": [item.as_dict() for item in traces],
|
|
198
|
+
"images": images.as_dict() if images else None,
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
failures = [params, *metrics, *traces]
|
|
202
|
+
if images:
|
|
203
|
+
failures.append(images)
|
|
204
|
+
ok = all(item.ok for item in failures)
|
|
205
|
+
return snapshot, ok
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def main() -> int:
|
|
209
|
+
args = parse_args()
|
|
210
|
+
snapshot, ok = collect_snapshot(args)
|
|
211
|
+
indent = 2 if args.pretty else None
|
|
212
|
+
print(json.dumps(snapshot, indent=indent, sort_keys=args.pretty))
|
|
213
|
+
return 0 if ok else 2
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
if __name__ == "__main__":
|
|
217
|
+
raise SystemExit(main())
|
|
@@ -137,6 +137,8 @@ celerybeat.pid
|
|
|
137
137
|
# Environments
|
|
138
138
|
.env
|
|
139
139
|
.envrc
|
|
140
|
+
.env*
|
|
141
|
+
.venv/
|
|
140
142
|
.venv
|
|
141
143
|
env/
|
|
142
144
|
venv/
|
|
@@ -188,6 +190,12 @@ cython_debug/
|
|
|
188
190
|
# you could uncomment the following to ignore the entire vscode folder
|
|
189
191
|
# .vscode/
|
|
190
192
|
|
|
193
|
+
# OS / editor
|
|
194
|
+
.DS_Store
|
|
195
|
+
Thumbs.db
|
|
196
|
+
*.tmp
|
|
197
|
+
*.swp
|
|
198
|
+
|
|
191
199
|
# Ruff stuff:
|
|
192
200
|
.ruff_cache/
|
|
193
201
|
|
|
@@ -210,4 +218,4 @@ __marimo__/
|
|
|
210
218
|
.specify/
|
|
211
219
|
|
|
212
220
|
# aim
|
|
213
|
-
data/
|
|
221
|
+
data/
|
|
@@ -77,6 +77,10 @@ Why `3.12`:
|
|
|
77
77
|
- Python 3.12 for development, runtime support `>=3.10,<3.13` + Python standard library, native Aim CLI (external runtime prerequisite for delegated commands), pytest for test automation (001-aim-command-passthrough)
|
|
78
78
|
- Python 3.12 for development, runtime support `>=3.10,<3.13` + Python standard library, Aim SDK from the dev dependency group for local development and tests (001-aim-command-passthrough)
|
|
79
79
|
- Existing local Aim repositories on disk, including repo roots that contain a `.aim` metadata directory (001-aim-command-passthrough)
|
|
80
|
+
- Python 3.12 for development, runtime support `>=3.10,<3.13` + `rich>=13.7`, `textual-image>=0.12.0` (already declared in (003-query-images-terminal-render)
|
|
81
|
+
- Existing local Aim repositories (read-only). Image bytes are read (003-query-images-terminal-render)
|
|
82
|
+
- Python 3.12 for development, runtime support `>=3.10,<3.13` + Python standard library, `numpy>=1.24`, `rich>=13.7`, `textual-image>=0.12.0`, existing Aim SDK usage for owned query commands; no new dependency planned (004-run-params-query)
|
|
83
|
+
- Existing local Aim repositories on disk (read-only); run params are read from Aim run metadata attributes under `.aim` (004-run-params-query)
|
|
80
84
|
|
|
81
85
|
## Recent Changes
|
|
82
86
|
- 001-aim-command-passthrough: Added Python 3.12 for development, runtime support `>=3.10,<3.13` + Python standard library, native Aim CLI (external runtime prerequisite for delegated commands), pytest for test automation
|