infini-cli 0.1.0__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.
@@ -0,0 +1,159 @@
1
+ Metadata-Version: 2.4
2
+ Name: infini-cli
3
+ Version: 0.1.0
4
+ Summary: INFINI — the open standard for agent loops. Write a Loopfile, run it on any engine.
5
+ Author: NickAiNYC and INFINI contributors
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/NickAiNYC/infini
8
+ Project-URL: Documentation, https://github.com/NickAiNYC/infini#readme
9
+ Project-URL: Repository, https://github.com/NickAiNYC/infini
10
+ Project-URL: Issues, https://github.com/NickAiNYC/infini/issues
11
+ Keywords: agents,loops,ai,standard,loopfile,infini
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Libraries
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ Requires-Dist: pyyaml>=6.0
24
+ Requires-Dist: jsonschema>=4.20
25
+ Requires-Dist: rich>=13.0
26
+ Requires-Dist: click>=8.1
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=7.0; extra == "dev"
29
+ Requires-Dist: pytest-cov; extra == "dev"
30
+ Provides-Extra: ui
31
+ Requires-Dist: flask>=3.0; extra == "ui"
32
+
33
+ # INFINI CLI
34
+
35
+ The reference implementation of the `infini` command-line tool.
36
+
37
+ > The CLI is the **INFINI Reference Engine**. It conforms to the same Loopfile spec as every other engine. The only asymmetry: it ships first with new spec features, since the spec is developed against it.
38
+
39
+ ---
40
+
41
+ ## Install
42
+
43
+ ```bash
44
+ pip install infini-cli
45
+
46
+ # With adapter extras
47
+ pip install infini-cli[hermes,openclaw]
48
+
49
+ # From source
50
+ git clone https://github.com/NickAiNYC/infini
51
+ cd infini/cli && pip install -e .
52
+ ```
53
+
54
+ Requires Python 3.10+.
55
+
56
+ ---
57
+
58
+ ## Commands
59
+
60
+ ```bash
61
+ infini validate [Loopfile] # check spec compliance
62
+ infini run [Loopfile] # execute a loop (--mock for no API key)
63
+ infini inspect [run_dir] # inspect a trace (--web opens Observatory, coming soon)
64
+ infini replay [run_dir] # time-travel debug from any step
65
+ infini diff [v1] [v2] # semantic diff between loops or traces
66
+ infini ui [trace] # launch the Observatory web app
67
+ infini engines # list detected adapters (reads adapter.yaml)
68
+ infini init [--target] # scaffold a minimal project (Loopfile, loops/, state/, runs/)
69
+ infini new <name> # create a new project scaffold
70
+ infini graph [Loopfile] # render a simple ASCII graph of steps
71
+ infini benchmark [Loopfile] # preview benchmark estimate (real profiling needs a run)
72
+ ```
73
+
74
+ ### Commands not yet implemented (planned)
75
+
76
+ ```bash
77
+ infini install [loop_ref] # pull from registry (planned — registry not yet live)
78
+ infini publish [Loopfile] # push to registry (planned)
79
+ infini ci [Loopfile] # run loop against fixtures (GitHub Action)
80
+ infini search [query] # search the registry (planned)
81
+ infini migrate [Loopfile] # migrate a Loopfile between spec versions
82
+ infini keys generate # generate a publisher signing keypair
83
+ ```
84
+
85
+ ### Mock mode
86
+
87
+ `infini run --mock` simulates LLM calls so you can run any Loopfile
88
+ without an API key. Useful for evaluation, CI, demos, and the conformance
89
+ suite. Mock mode is deterministic: same Loopfile + same seed = same output.
90
+
91
+ ---
92
+
93
+ ## Conformance
94
+
95
+ The CLI implements:
96
+
97
+ | Capability | Status |
98
+ | ---------------- | :----: |
99
+ | Parse Loopfile | ✅ |
100
+ | Run Loop | ✅ |
101
+ | Verify | ✅ |
102
+ | Inspect Trace | ✅ |
103
+ | Replay | ✅ |
104
+ | Diff | ✅ |
105
+
106
+ This makes the CLI the **canonical conformance reference**. If your adapter disagrees with the CLI on a spec edge case, the CLI is right until an RFC says otherwise.
107
+
108
+ ---
109
+
110
+ ## Architecture
111
+
112
+ ```
113
+ cli/
114
+ ├── README.md # you are here
115
+ ├── pyproject.toml # package metadata
116
+ ├── src/infini/
117
+ │ ├── __init__.py
118
+ │ ├── main.py # entrypoint
119
+ │ ├── parse.py # Loopfile parser
120
+ │ ├── validate.py # JSON Schema validator
121
+ │ ├── run.py # reference engine
122
+ │ ├── inspect.py # trace inspector (Loop Observatory)
123
+ │ ├── replay.py # time-travel debugger
124
+ │ ├── diff.py # semantic diff
125
+ │ ├── registry.py # publish/install/search
126
+ │ ├── ci.py # CI mode
127
+ │ ├── migrate.py # spec migration
128
+ │ └── keys.py # signing key management
129
+ └── tests/
130
+ ├── conformance/ # spec conformance suite
131
+ ├── fixtures/ # example Loopfiles
132
+ └── expected/ # expected trace shapes
133
+ ```
134
+
135
+ The full source ships with the next CLI release. This README documents the contract.
136
+
137
+ ---
138
+
139
+ ## The Loop Observatory
140
+
141
+ `infini inspect <run_dir>` opens the Loop Observatory — the signature feature.
142
+
143
+ The Observatory shows, for any run:
144
+
145
+ - the graph of decisions taken,
146
+ - every verification checkpoint and its verdict,
147
+ - total runtime, token count, and dollar cost,
148
+ - artifacts produced at each step,
149
+ - where the loop failed (if it did), and what was retried,
150
+ - what changed between iterations,
151
+ - governance events (Hermes) and tool calls (OpenClaw) in a swimlane view.
152
+
153
+ The Inspector ships today. The full UI (annotated timeline, cost waterfall, artifact gallery, replay studio) is in preview.
154
+
155
+ ---
156
+
157
+ ## License
158
+
159
+ MIT. See [repository LICENSE](../LICENSE).
@@ -0,0 +1,127 @@
1
+ # INFINI CLI
2
+
3
+ The reference implementation of the `infini` command-line tool.
4
+
5
+ > The CLI is the **INFINI Reference Engine**. It conforms to the same Loopfile spec as every other engine. The only asymmetry: it ships first with new spec features, since the spec is developed against it.
6
+
7
+ ---
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pip install infini-cli
13
+
14
+ # With adapter extras
15
+ pip install infini-cli[hermes,openclaw]
16
+
17
+ # From source
18
+ git clone https://github.com/NickAiNYC/infini
19
+ cd infini/cli && pip install -e .
20
+ ```
21
+
22
+ Requires Python 3.10+.
23
+
24
+ ---
25
+
26
+ ## Commands
27
+
28
+ ```bash
29
+ infini validate [Loopfile] # check spec compliance
30
+ infini run [Loopfile] # execute a loop (--mock for no API key)
31
+ infini inspect [run_dir] # inspect a trace (--web opens Observatory, coming soon)
32
+ infini replay [run_dir] # time-travel debug from any step
33
+ infini diff [v1] [v2] # semantic diff between loops or traces
34
+ infini ui [trace] # launch the Observatory web app
35
+ infini engines # list detected adapters (reads adapter.yaml)
36
+ infini init [--target] # scaffold a minimal project (Loopfile, loops/, state/, runs/)
37
+ infini new <name> # create a new project scaffold
38
+ infini graph [Loopfile] # render a simple ASCII graph of steps
39
+ infini benchmark [Loopfile] # preview benchmark estimate (real profiling needs a run)
40
+ ```
41
+
42
+ ### Commands not yet implemented (planned)
43
+
44
+ ```bash
45
+ infini install [loop_ref] # pull from registry (planned — registry not yet live)
46
+ infini publish [Loopfile] # push to registry (planned)
47
+ infini ci [Loopfile] # run loop against fixtures (GitHub Action)
48
+ infini search [query] # search the registry (planned)
49
+ infini migrate [Loopfile] # migrate a Loopfile between spec versions
50
+ infini keys generate # generate a publisher signing keypair
51
+ ```
52
+
53
+ ### Mock mode
54
+
55
+ `infini run --mock` simulates LLM calls so you can run any Loopfile
56
+ without an API key. Useful for evaluation, CI, demos, and the conformance
57
+ suite. Mock mode is deterministic: same Loopfile + same seed = same output.
58
+
59
+ ---
60
+
61
+ ## Conformance
62
+
63
+ The CLI implements:
64
+
65
+ | Capability | Status |
66
+ | ---------------- | :----: |
67
+ | Parse Loopfile | ✅ |
68
+ | Run Loop | ✅ |
69
+ | Verify | ✅ |
70
+ | Inspect Trace | ✅ |
71
+ | Replay | ✅ |
72
+ | Diff | ✅ |
73
+
74
+ This makes the CLI the **canonical conformance reference**. If your adapter disagrees with the CLI on a spec edge case, the CLI is right until an RFC says otherwise.
75
+
76
+ ---
77
+
78
+ ## Architecture
79
+
80
+ ```
81
+ cli/
82
+ ├── README.md # you are here
83
+ ├── pyproject.toml # package metadata
84
+ ├── src/infini/
85
+ │ ├── __init__.py
86
+ │ ├── main.py # entrypoint
87
+ │ ├── parse.py # Loopfile parser
88
+ │ ├── validate.py # JSON Schema validator
89
+ │ ├── run.py # reference engine
90
+ │ ├── inspect.py # trace inspector (Loop Observatory)
91
+ │ ├── replay.py # time-travel debugger
92
+ │ ├── diff.py # semantic diff
93
+ │ ├── registry.py # publish/install/search
94
+ │ ├── ci.py # CI mode
95
+ │ ├── migrate.py # spec migration
96
+ │ └── keys.py # signing key management
97
+ └── tests/
98
+ ├── conformance/ # spec conformance suite
99
+ ├── fixtures/ # example Loopfiles
100
+ └── expected/ # expected trace shapes
101
+ ```
102
+
103
+ The full source ships with the next CLI release. This README documents the contract.
104
+
105
+ ---
106
+
107
+ ## The Loop Observatory
108
+
109
+ `infini inspect <run_dir>` opens the Loop Observatory — the signature feature.
110
+
111
+ The Observatory shows, for any run:
112
+
113
+ - the graph of decisions taken,
114
+ - every verification checkpoint and its verdict,
115
+ - total runtime, token count, and dollar cost,
116
+ - artifacts produced at each step,
117
+ - where the loop failed (if it did), and what was retried,
118
+ - what changed between iterations,
119
+ - governance events (Hermes) and tool calls (OpenClaw) in a swimlane view.
120
+
121
+ The Inspector ships today. The full UI (annotated timeline, cost waterfall, artifact gallery, replay studio) is in preview.
122
+
123
+ ---
124
+
125
+ ## License
126
+
127
+ MIT. See [repository LICENSE](../LICENSE).
@@ -0,0 +1,49 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "infini-cli"
7
+ version = "0.1.0"
8
+ description = "INFINI — the open standard for agent loops. Write a Loopfile, run it on any engine."
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.10"
12
+ authors = [{ name = "NickAiNYC and INFINI contributors" }]
13
+ keywords = ["agents", "loops", "ai", "standard", "loopfile", "infini"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Environment :: Console",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Topic :: Software Development :: Libraries",
24
+ ]
25
+ dependencies = [
26
+ "pyyaml>=6.0",
27
+ "jsonschema>=4.20",
28
+ "rich>=13.0",
29
+ "click>=8.1",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ dev = ["pytest>=7.0", "pytest-cov"]
34
+ ui = ["flask>=3.0"]
35
+
36
+ [project.scripts]
37
+ infini = "infini.cli:main"
38
+
39
+ [project.urls]
40
+ Homepage = "https://github.com/NickAiNYC/infini"
41
+ Documentation = "https://github.com/NickAiNYC/infini#readme"
42
+ Repository = "https://github.com/NickAiNYC/infini"
43
+ Issues = "https://github.com/NickAiNYC/infini/issues"
44
+
45
+ [tool.setuptools.packages.find]
46
+ where = ["src"]
47
+
48
+ [tool.setuptools.package-data]
49
+ infini = ["schema.json"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,6 @@
1
+ """INFINI — the open standard for agent loops.
2
+
3
+ Write a Loopfile, run it on any engine.
4
+ """
5
+
6
+ __version__ = "0.1.0"
@@ -0,0 +1,4 @@
1
+ from infini.cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1,68 @@
1
+ """Adapter discovery and capability metadata.
2
+
3
+ Scans the adapters/ directory for adapter.yaml manifests and reports
4
+ actual capabilities (parse, run, verify, inspect, replay, diff) instead
5
+ of just directory names.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ from pathlib import Path
10
+ from typing import Optional
11
+
12
+ import yaml
13
+
14
+
15
+ def find_adapters_dir(start: Optional[Path] = None) -> Optional[Path]:
16
+ """Search upwards from start (or cwd) for an adapters/ directory."""
17
+ p = Path(start or Path.cwd()).resolve()
18
+ root = p.anchor
19
+ while True:
20
+ candidate = p / "adapters"
21
+ if candidate.is_dir():
22
+ return candidate
23
+ if str(p) == root:
24
+ return None
25
+ p = p.parent
26
+
27
+
28
+ def load_adapter_manifest(adapter_dir: Path) -> dict | None:
29
+ """Load an adapter's adapter.yaml manifest. Returns None if not found."""
30
+ manifest_path = adapter_dir / "adapter.yaml"
31
+ if not manifest_path.exists():
32
+ return None
33
+ try:
34
+ with manifest_path.open("r", encoding="utf-8") as fh:
35
+ data = yaml.safe_load(fh)
36
+ return data if isinstance(data, dict) else None
37
+ except Exception:
38
+ return None
39
+
40
+
41
+ def detect_adapters(base: Optional[Path] = None) -> list[dict]:
42
+ """Scan for adapters and return their manifests.
43
+
44
+ Returns a list of dicts, each with at minimum:
45
+ - name: adapter directory name
46
+ - path: absolute path to the adapter directory
47
+ - manifest: the parsed adapter.yaml (or None if no manifest)
48
+ - capabilities: list of supported capability strings (from manifest, or [])
49
+ """
50
+ adapters_dir = find_adapters_dir(base)
51
+ if not adapters_dir:
52
+ return []
53
+
54
+ results = []
55
+ for p in sorted(adapters_dir.iterdir()):
56
+ if not p.is_dir():
57
+ continue
58
+ manifest = load_adapter_manifest(p)
59
+ caps = []
60
+ if manifest and isinstance(manifest.get("capabilities"), dict):
61
+ caps = [k for k, v in manifest["capabilities"].items() if v is True]
62
+ results.append({
63
+ "name": p.name,
64
+ "path": str(p),
65
+ "manifest": manifest,
66
+ "capabilities": caps,
67
+ })
68
+ return results