ouroboros-ai 0.2.3__py3-none-any.whl → 0.4.0__py3-none-any.whl
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.
Potentially problematic release.
This version of ouroboros-ai might be problematic. Click here for more details.
- ouroboros/__init__.py +1 -1
- ouroboros/bigbang/__init__.py +9 -0
- ouroboros/bigbang/interview.py +16 -18
- ouroboros/bigbang/ontology.py +180 -0
- ouroboros/cli/commands/__init__.py +2 -0
- ouroboros/cli/commands/init.py +162 -97
- ouroboros/cli/commands/mcp.py +161 -0
- ouroboros/cli/commands/run.py +165 -27
- ouroboros/cli/main.py +2 -1
- ouroboros/core/ontology_aspect.py +455 -0
- ouroboros/core/ontology_questions.py +462 -0
- ouroboros/evaluation/__init__.py +16 -1
- ouroboros/evaluation/consensus.py +569 -11
- ouroboros/evaluation/models.py +81 -0
- ouroboros/events/ontology.py +135 -0
- ouroboros/mcp/__init__.py +83 -0
- ouroboros/mcp/client/__init__.py +20 -0
- ouroboros/mcp/client/adapter.py +632 -0
- ouroboros/mcp/client/manager.py +600 -0
- ouroboros/mcp/client/protocol.py +161 -0
- ouroboros/mcp/errors.py +377 -0
- ouroboros/mcp/resources/__init__.py +22 -0
- ouroboros/mcp/resources/handlers.py +328 -0
- ouroboros/mcp/server/__init__.py +21 -0
- ouroboros/mcp/server/adapter.py +408 -0
- ouroboros/mcp/server/protocol.py +291 -0
- ouroboros/mcp/server/security.py +636 -0
- ouroboros/mcp/tools/__init__.py +24 -0
- ouroboros/mcp/tools/definitions.py +351 -0
- ouroboros/mcp/tools/registry.py +269 -0
- ouroboros/mcp/types.py +333 -0
- ouroboros/orchestrator/__init__.py +31 -0
- ouroboros/orchestrator/events.py +40 -0
- ouroboros/orchestrator/mcp_config.py +419 -0
- ouroboros/orchestrator/mcp_tools.py +483 -0
- ouroboros/orchestrator/runner.py +119 -2
- ouroboros/providers/claude_code_adapter.py +75 -0
- ouroboros/strategies/__init__.py +23 -0
- ouroboros/strategies/devil_advocate.py +197 -0
- {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/METADATA +73 -17
- {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/RECORD +44 -19
- {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/WHEEL +0 -0
- {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/entry_points.txt +0 -0
- {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -10,11 +10,24 @@ Usage:
|
|
|
10
10
|
messages=[Message(role=MessageRole.USER, content="Hello!")],
|
|
11
11
|
config=CompletionConfig(model="claude-sonnet-4-20250514"),
|
|
12
12
|
)
|
|
13
|
+
|
|
14
|
+
Custom CLI Path:
|
|
15
|
+
You can specify a custom Claude CLI binary path to use instead of
|
|
16
|
+
the SDK's bundled CLI. This is useful for:
|
|
17
|
+
- Using an instrumented CLI wrapper (e.g., for OTEL tracing)
|
|
18
|
+
- Testing with a specific CLI version
|
|
19
|
+
- Using a locally built CLI
|
|
20
|
+
|
|
21
|
+
Set via constructor parameter or environment variable:
|
|
22
|
+
adapter = ClaudeCodeAdapter(cli_path="/path/to/claude")
|
|
23
|
+
# or
|
|
24
|
+
export OUROBOROS_CLI_PATH=/path/to/claude
|
|
13
25
|
"""
|
|
14
26
|
|
|
15
27
|
from __future__ import annotations
|
|
16
28
|
|
|
17
29
|
import os
|
|
30
|
+
from pathlib import Path
|
|
18
31
|
|
|
19
32
|
import structlog
|
|
20
33
|
|
|
@@ -38,6 +51,10 @@ class ClaudeCodeAdapter:
|
|
|
38
51
|
the Claude Agent SDK under the hood. This allows users to leverage
|
|
39
52
|
their Claude Code Max Plan subscription without needing separate API keys.
|
|
40
53
|
|
|
54
|
+
Attributes:
|
|
55
|
+
cli_path: Path to the Claude CLI binary. If not set, the SDK will
|
|
56
|
+
use its bundled CLI. Set this to use a custom/instrumented CLI.
|
|
57
|
+
|
|
41
58
|
Example:
|
|
42
59
|
adapter = ClaudeCodeAdapter()
|
|
43
60
|
result = await adapter.complete(
|
|
@@ -46,11 +63,15 @@ class ClaudeCodeAdapter:
|
|
|
46
63
|
)
|
|
47
64
|
if result.is_ok:
|
|
48
65
|
print(result.value.content)
|
|
66
|
+
|
|
67
|
+
Example with custom CLI:
|
|
68
|
+
adapter = ClaudeCodeAdapter(cli_path="/usr/local/bin/claude")
|
|
49
69
|
"""
|
|
50
70
|
|
|
51
71
|
def __init__(
|
|
52
72
|
self,
|
|
53
73
|
permission_mode: str = "default",
|
|
74
|
+
cli_path: str | Path | None = None,
|
|
54
75
|
) -> None:
|
|
55
76
|
"""Initialize Claude Code adapter.
|
|
56
77
|
|
|
@@ -58,12 +79,65 @@ class ClaudeCodeAdapter:
|
|
|
58
79
|
permission_mode: Permission mode for SDK operations.
|
|
59
80
|
- "default": Standard permissions
|
|
60
81
|
- "acceptEdits": Auto-approve edits (not needed for interview)
|
|
82
|
+
cli_path: Path to the Claude CLI binary. If not provided,
|
|
83
|
+
checks OUROBOROS_CLI_PATH env var, then falls back to
|
|
84
|
+
SDK's bundled CLI.
|
|
61
85
|
"""
|
|
62
86
|
self._permission_mode: str = permission_mode
|
|
87
|
+
self._cli_path: Path | None = self._resolve_cli_path(cli_path)
|
|
63
88
|
log.info(
|
|
64
89
|
"claude_code_adapter.initialized",
|
|
65
90
|
permission_mode=permission_mode,
|
|
91
|
+
cli_path=str(self._cli_path) if self._cli_path else None,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
def _resolve_cli_path(self, cli_path: str | Path | None) -> Path | None:
|
|
95
|
+
"""Resolve the CLI path from parameter or environment variable.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
cli_path: Explicit CLI path from constructor.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
Resolved Path if set and exists, None otherwise (falls back to SDK default).
|
|
102
|
+
"""
|
|
103
|
+
# Priority: explicit parameter > environment variable > None (SDK default)
|
|
104
|
+
path_str = str(cli_path) if cli_path else os.environ.get("OUROBOROS_CLI_PATH", "")
|
|
105
|
+
path_str = path_str.strip()
|
|
106
|
+
|
|
107
|
+
if not path_str:
|
|
108
|
+
return None
|
|
109
|
+
|
|
110
|
+
resolved = Path(path_str).expanduser().resolve()
|
|
111
|
+
|
|
112
|
+
if not resolved.exists():
|
|
113
|
+
log.warning(
|
|
114
|
+
"claude_code_adapter.cli_path_not_found",
|
|
115
|
+
cli_path=str(resolved),
|
|
116
|
+
fallback="using SDK bundled CLI",
|
|
117
|
+
)
|
|
118
|
+
return None
|
|
119
|
+
|
|
120
|
+
if not resolved.is_file():
|
|
121
|
+
log.warning(
|
|
122
|
+
"claude_code_adapter.cli_path_not_file",
|
|
123
|
+
cli_path=str(resolved),
|
|
124
|
+
fallback="using SDK bundled CLI",
|
|
125
|
+
)
|
|
126
|
+
return None
|
|
127
|
+
|
|
128
|
+
if not os.access(resolved, os.X_OK):
|
|
129
|
+
log.warning(
|
|
130
|
+
"claude_code_adapter.cli_not_executable",
|
|
131
|
+
cli_path=str(resolved),
|
|
132
|
+
fallback="using SDK bundled CLI",
|
|
133
|
+
)
|
|
134
|
+
return None
|
|
135
|
+
|
|
136
|
+
log.debug(
|
|
137
|
+
"claude_code_adapter.using_custom_cli",
|
|
138
|
+
cli_path=str(resolved),
|
|
66
139
|
)
|
|
140
|
+
return resolved
|
|
67
141
|
|
|
68
142
|
async def complete(
|
|
69
143
|
self,
|
|
@@ -107,6 +181,7 @@ class ClaudeCodeAdapter:
|
|
|
107
181
|
allowed_tools=[], # No tools - pure conversation
|
|
108
182
|
permission_mode=self._permission_mode, # type: ignore[arg-type]
|
|
109
183
|
cwd=os.getcwd(),
|
|
184
|
+
cli_path=self._cli_path,
|
|
110
185
|
)
|
|
111
186
|
|
|
112
187
|
# Collect the response
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Ontological Analysis Strategies.
|
|
2
|
+
|
|
3
|
+
This module contains strategy implementations for the AOP-based
|
|
4
|
+
ontological framework. Each strategy is designed for a specific
|
|
5
|
+
join point (phase) in Ouroboros.
|
|
6
|
+
|
|
7
|
+
Available Strategies:
|
|
8
|
+
- DevilAdvocateStrategy: Consensus phase (Phase 4)
|
|
9
|
+
- InterviewOntologyStrategy: Interview phase (Phase 0) [planned]
|
|
10
|
+
- ContrarianStrategy: Resilience phase (Phase 3) [planned]
|
|
11
|
+
|
|
12
|
+
Reference: docs/ontological-framework/aop-design.md
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from ouroboros.strategies.devil_advocate import (
|
|
16
|
+
ConsensusContext,
|
|
17
|
+
DevilAdvocateStrategy,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"ConsensusContext",
|
|
22
|
+
"DevilAdvocateStrategy",
|
|
23
|
+
]
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""Devil's Advocate Strategy for Consensus Phase.
|
|
2
|
+
|
|
3
|
+
This strategy implements ontological analysis for the Consensus phase (Phase 4).
|
|
4
|
+
The Devil's Advocate critically examines whether a solution addresses the
|
|
5
|
+
ROOT CAUSE or merely treats SYMPTOMS.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
strategy = DevilAdvocateStrategy(llm_adapter)
|
|
9
|
+
aspect = OntologicalAspect(strategy=strategy)
|
|
10
|
+
|
|
11
|
+
result = await aspect.execute(
|
|
12
|
+
context=ConsensusContext(artifact=..., goal=...),
|
|
13
|
+
core_operation=lambda ctx: consensus.deliberate(ctx),
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
Reference: docs/ontological-framework/aop-design.md
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from dataclasses import dataclass
|
|
22
|
+
import hashlib
|
|
23
|
+
import json
|
|
24
|
+
from typing import TYPE_CHECKING
|
|
25
|
+
|
|
26
|
+
from ouroboros.core.ontology_aspect import (
|
|
27
|
+
AnalysisResult,
|
|
28
|
+
OntologicalJoinPoint,
|
|
29
|
+
)
|
|
30
|
+
from ouroboros.core.ontology_questions import (
|
|
31
|
+
OntologicalQuestionType,
|
|
32
|
+
analyze_ontologically,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
if TYPE_CHECKING:
|
|
36
|
+
from ouroboros.providers.base import LLMAdapter
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass(frozen=True, slots=True)
|
|
40
|
+
class ConsensusContext:
|
|
41
|
+
"""Context for consensus phase ontological analysis.
|
|
42
|
+
|
|
43
|
+
Attributes:
|
|
44
|
+
artifact: The artifact/solution being evaluated.
|
|
45
|
+
goal: The original goal or problem statement.
|
|
46
|
+
current_ac: Current acceptance criteria.
|
|
47
|
+
constraints: Any constraints on the solution.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
artifact: str
|
|
51
|
+
goal: str
|
|
52
|
+
current_ac: str = ""
|
|
53
|
+
constraints: tuple[str, ...] = ()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass
|
|
57
|
+
class DevilAdvocateStrategy:
|
|
58
|
+
"""Strategy for Consensus phase (Phase 4).
|
|
59
|
+
|
|
60
|
+
The Devil's Advocate role: Critically examine whether
|
|
61
|
+
the solution addresses the ROOT CAUSE or just symptoms.
|
|
62
|
+
|
|
63
|
+
This strategy uses the centralized analyze_ontologically() function
|
|
64
|
+
from ontology_questions.py, focusing on ROOT_CAUSE and ESSENCE questions.
|
|
65
|
+
|
|
66
|
+
Attributes:
|
|
67
|
+
llm_adapter: LLM adapter for analysis.
|
|
68
|
+
model: Model to use (default: gemini-2.0-flash).
|
|
69
|
+
confidence_threshold: Minimum confidence to pass (default: 0.7).
|
|
70
|
+
temperature: Sampling temperature for LLM (default: 0.3).
|
|
71
|
+
max_tokens: Maximum tokens for LLM response (default: 2048).
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
llm_adapter: LLMAdapter
|
|
75
|
+
model: str = "openrouter/google/gemini-2.0-flash-001"
|
|
76
|
+
confidence_threshold: float = 0.7
|
|
77
|
+
temperature: float = 0.3
|
|
78
|
+
max_tokens: int = 2048
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def join_point(self) -> OntologicalJoinPoint:
|
|
82
|
+
"""This strategy is for the Consensus phase."""
|
|
83
|
+
return OntologicalJoinPoint.CONSENSUS
|
|
84
|
+
|
|
85
|
+
def get_cache_key(self, context: ConsensusContext) -> str:
|
|
86
|
+
"""Compute cache key from artifact and goal hash.
|
|
87
|
+
|
|
88
|
+
Only artifact content and goal matter for caching -
|
|
89
|
+
the same solution for the same problem should get the same result.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
context: The consensus context.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
SHA256 hash of artifact + goal (first 16 chars).
|
|
96
|
+
"""
|
|
97
|
+
cache_data = {
|
|
98
|
+
"artifact": context.artifact,
|
|
99
|
+
"goal": context.goal,
|
|
100
|
+
}
|
|
101
|
+
return hashlib.sha256(
|
|
102
|
+
json.dumps(cache_data, sort_keys=True).encode()
|
|
103
|
+
).hexdigest()[:16]
|
|
104
|
+
|
|
105
|
+
async def analyze(self, context: ConsensusContext) -> AnalysisResult:
|
|
106
|
+
"""Analyze solution using Devil's Advocate lens.
|
|
107
|
+
|
|
108
|
+
Applies ontological analysis focusing on:
|
|
109
|
+
- Is this solving the root cause or just a symptom?
|
|
110
|
+
- What is the essential nature of the problem?
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
context: The consensus context with artifact and goal.
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
AnalysisResult with validity based on is_root_problem.
|
|
117
|
+
"""
|
|
118
|
+
# Build analysis context string
|
|
119
|
+
analysis_context = self._build_analysis_context(context)
|
|
120
|
+
|
|
121
|
+
# Use centralized ontological analysis
|
|
122
|
+
insight_result = await analyze_ontologically(
|
|
123
|
+
llm_adapter=self.llm_adapter,
|
|
124
|
+
context=analysis_context,
|
|
125
|
+
question_types=(
|
|
126
|
+
OntologicalQuestionType.ROOT_CAUSE,
|
|
127
|
+
OntologicalQuestionType.ESSENCE,
|
|
128
|
+
),
|
|
129
|
+
model=self.model,
|
|
130
|
+
temperature=self.temperature,
|
|
131
|
+
max_tokens=self.max_tokens,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# Handle LLM failure
|
|
135
|
+
if insight_result.is_err:
|
|
136
|
+
# Return invalid with error info - let Aspect handle retry/fail
|
|
137
|
+
return AnalysisResult.invalid(
|
|
138
|
+
reasoning=[f"Analysis failed: {insight_result.error.message}"],
|
|
139
|
+
suggestions=["Retry the analysis", "Check LLM provider status"],
|
|
140
|
+
confidence=0.0,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
insight = insight_result.value
|
|
144
|
+
|
|
145
|
+
# Convert OntologicalInsight to AnalysisResult
|
|
146
|
+
if insight.is_root_problem and insight.confidence >= self.confidence_threshold:
|
|
147
|
+
return AnalysisResult.valid(
|
|
148
|
+
confidence=insight.confidence,
|
|
149
|
+
reasoning=[insight.reasoning],
|
|
150
|
+
)
|
|
151
|
+
else:
|
|
152
|
+
suggestions = list(insight.hidden_assumptions)
|
|
153
|
+
if not insight.is_root_problem:
|
|
154
|
+
suggestions.insert(0, "This appears to treat symptoms, not root cause")
|
|
155
|
+
if insight.confidence < self.confidence_threshold:
|
|
156
|
+
suggestions.append(
|
|
157
|
+
f"Low confidence ({insight.confidence:.2f}). Consider more analysis."
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
return AnalysisResult.invalid(
|
|
161
|
+
reasoning=[insight.reasoning],
|
|
162
|
+
suggestions=tuple(suggestions),
|
|
163
|
+
confidence=insight.confidence,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
def _build_analysis_context(self, context: ConsensusContext) -> str:
|
|
167
|
+
"""Build the context string for ontological analysis.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
context: The consensus context.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
Formatted context string for analysis.
|
|
174
|
+
"""
|
|
175
|
+
parts = [
|
|
176
|
+
"## Goal/Problem",
|
|
177
|
+
context.goal,
|
|
178
|
+
"",
|
|
179
|
+
"## Proposed Solution/Artifact",
|
|
180
|
+
context.artifact,
|
|
181
|
+
]
|
|
182
|
+
|
|
183
|
+
if context.current_ac:
|
|
184
|
+
parts.extend(["", "## Acceptance Criteria", context.current_ac])
|
|
185
|
+
|
|
186
|
+
if context.constraints:
|
|
187
|
+
parts.extend(
|
|
188
|
+
["", "## Constraints", *[f"- {c}" for c in context.constraints]]
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
return "\n".join(parts)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
__all__ = [
|
|
195
|
+
"ConsensusContext",
|
|
196
|
+
"DevilAdvocateStrategy",
|
|
197
|
+
]
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ouroboros-ai
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Self-Improving AI Workflow System
|
|
5
5
|
Author-email: Q00 <jqyu.lee@gmail.com>
|
|
6
6
|
License-File: LICENSE
|
|
7
7
|
Requires-Python: >=3.14
|
|
8
8
|
Requires-Dist: aiosqlite>=0.20.0
|
|
9
|
+
Requires-Dist: cachetools>=5.0.0
|
|
9
10
|
Requires-Dist: claude-agent-sdk>=0.1.0
|
|
10
11
|
Requires-Dist: httpx>=0.27.0
|
|
11
12
|
Requires-Dist: litellm>=1.80.0
|
|
13
|
+
Requires-Dist: mcp>=1.26.0
|
|
12
14
|
Requires-Dist: pydantic>=2.0.0
|
|
13
15
|
Requires-Dist: pyyaml>=6.0.0
|
|
14
16
|
Requires-Dist: rich>=13.0.0
|
|
@@ -41,18 +43,26 @@ Description-Content-Type: text/markdown
|
|
|
41
43
|
<em>The serpent that devours itself to be reborn anew.</em>
|
|
42
44
|
</p>
|
|
43
45
|
|
|
46
|
+
<p align="center">
|
|
47
|
+
<a href="https://pypi.org/project/ouroboros-ai/"><img src="https://img.shields.io/pypi/v/ouroboros-ai?color=blue" alt="PyPI"></a>
|
|
48
|
+
<a href="https://python.org"><img src="https://img.shields.io/badge/python-3.14+-blue" alt="Python"></a>
|
|
49
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="License"></a>
|
|
50
|
+
</p>
|
|
51
|
+
|
|
44
52
|
<p align="center">
|
|
45
53
|
<a href="#-philosophy">Philosophy</a> •
|
|
46
54
|
<a href="#-the-six-phases">Phases</a> •
|
|
47
55
|
<a href="#-architecture">Architecture</a> •
|
|
56
|
+
<a href="#-prerequisites">Prerequisites</a> •
|
|
48
57
|
<a href="#-quick-start">Start</a> •
|
|
49
|
-
<a href="#-
|
|
58
|
+
<a href="#-roadmap">Roadmap</a> •
|
|
59
|
+
<a href="#-contributing">Contributing</a>
|
|
50
60
|
</p>
|
|
51
61
|
|
|
52
62
|
<br/>
|
|
53
63
|
|
|
54
64
|
<p align="center">
|
|
55
|
-
<code>
|
|
65
|
+
<code>75 modules</code> · <code>1,341 tests</code> · <code>97%+ coverage</code>
|
|
56
66
|
</p>
|
|
57
67
|
|
|
58
68
|
<br/>
|
|
@@ -236,7 +246,7 @@ These iterate until a **Seed** crystallizes—a specification with `Ambiguity
|
|
|
236
246
|
┃ └────┬────┘ ┃
|
|
237
247
|
┃ │ Stage 1: Mechanical ($0) — lint, build, test ┃
|
|
238
248
|
┃ │ Stage 2: Semantic ($$) — AC compliance, drift ┃
|
|
239
|
-
┃ │ Stage 3: Consensus ($$$$) —
|
|
249
|
+
┃ │ Stage 3: Consensus ($$$$) — Advocate/Devil/Judge debate ┃
|
|
240
250
|
┃ ▼ ┃
|
|
241
251
|
┃ ┌─────────┐ ┃
|
|
242
252
|
┃ │ PHASE 5 │ S E C O N D A R Y L O O P ┃
|
|
@@ -304,9 +314,9 @@ def select_approach(task):
|
|
|
304
314
|
```
|
|
305
315
|
src/ouroboros/
|
|
306
316
|
│
|
|
307
|
-
├── core/ ◆ The essence: types, errors, seed,
|
|
317
|
+
├── core/ ◆ The essence: types, errors, seed, ontology
|
|
308
318
|
│
|
|
309
|
-
├── bigbang/ ◇ Phase 0: Interview → Ambiguity → Seed
|
|
319
|
+
├── bigbang/ ◇ Phase 0: Interview → Ontology → Ambiguity → Seed
|
|
310
320
|
│
|
|
311
321
|
├── routing/ ◇ Phase 1: PAL router, complexity, tiers
|
|
312
322
|
│
|
|
@@ -349,10 +359,11 @@ src/ouroboros/
|
|
|
349
359
|
| **THE RESEARCHER** | *"Stop coding. Read the docs."* | Knowledge gap detected | Search, read documentation, find examples |
|
|
350
360
|
| **THE SIMPLIFIER** | *"Cut scope in half. Return to MVP."* | Overengineering detected | Remove features, reduce complexity |
|
|
351
361
|
| **THE ARCHITECT** | *"Question the foundation. Rebuild if needed."* | Structural issues | Redesign, refactor core assumptions |
|
|
362
|
+
| **THE CONTRARIAN** | *"What if we're solving the wrong problem?"* | Root cause unclear | Challenge assumptions using ontological questions |
|
|
352
363
|
|
|
353
364
|
<br/>
|
|
354
365
|
|
|
355
|
-
|
|
366
|
+
**How it works**: Stagnation Detection (4 patterns) → Persona Rotation → Retry with fresh perspective
|
|
356
367
|
|
|
357
368
|
<br/>
|
|
358
369
|
|
|
@@ -415,6 +426,22 @@ not to restart, but to **re-crystallize** with new understanding.
|
|
|
415
426
|
|
|
416
427
|
<br/>
|
|
417
428
|
|
|
429
|
+
## ◈ Prerequisites
|
|
430
|
+
|
|
431
|
+
<br/>
|
|
432
|
+
|
|
433
|
+
| Requirement | Description |
|
|
434
|
+
|-------------|-------------|
|
|
435
|
+
| **Python 3.14+** | Required (uses latest language features) |
|
|
436
|
+
| **Claude Code Max Plan** | For orchestrator mode (no API key needed) |
|
|
437
|
+
| **OR API Key** | OpenRouter, Anthropic, or OpenAI for LiteLLM mode |
|
|
438
|
+
|
|
439
|
+
<br/>
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
<br/>
|
|
444
|
+
|
|
418
445
|
## ◈ Installation
|
|
419
446
|
|
|
420
447
|
<br/>
|
|
@@ -476,7 +503,7 @@ uv run ouroboros init start "I want to build a task management CLI"
|
|
|
476
503
|
uv run ouroboros status health
|
|
477
504
|
```
|
|
478
505
|
|
|
479
|
-
> 📖 **[Full Guide: Running with Claude Code](docs/running-with-claude-code.md)**
|
|
506
|
+
> 📖 **[Full Guide: Running with Claude Code](docs/running-with-claude-code.md)** | **[CLI Reference](docs/cli-reference.md)**
|
|
480
507
|
|
|
481
508
|
<br/>
|
|
482
509
|
|
|
@@ -563,22 +590,51 @@ uv run ruff format src/
|
|
|
563
590
|
|
|
564
591
|
<br/>
|
|
565
592
|
|
|
593
|
+
## ◈ Contributing
|
|
594
|
+
|
|
595
|
+
<br/>
|
|
596
|
+
|
|
597
|
+
Contributions are welcome! Please see:
|
|
598
|
+
|
|
599
|
+
- **Issues**: [GitHub Issues](https://github.com/Q00/ouroboros/issues) for bugs and feature requests
|
|
600
|
+
- **Discussions**: [GitHub Discussions](https://github.com/Q00/ouroboros/discussions) for questions and ideas
|
|
601
|
+
|
|
602
|
+
<br/>
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
<br/>
|
|
607
|
+
|
|
566
608
|
## ◈ Roadmap
|
|
567
609
|
|
|
568
610
|
<br/>
|
|
569
611
|
|
|
612
|
+
### Completed
|
|
613
|
+
|
|
570
614
|
```
|
|
571
|
-
[■■■■■■■■■■] Epic 0 Foundation
|
|
572
|
-
[■■■■■■■■■■] Epic 1 Big Bang
|
|
573
|
-
[■■■■■■■■■■] Epic 2 PAL Router
|
|
574
|
-
[■■■■■■■■■■] Epic 3 Double Diamond
|
|
575
|
-
[■■■■■■■■■■] Epic 4 Resilience
|
|
576
|
-
[■■■■■■■■■■] Epic 5 Evaluation
|
|
577
|
-
[■■■■■■■■■■] Epic 6 Drift Control
|
|
578
|
-
[■■■■■■■■■■] Epic 7 Secondary Loop
|
|
579
|
-
[■■■■■■■■■■] Epic 8 Orchestrator
|
|
615
|
+
[■■■■■■■■■■] Epic 0 Foundation ✓
|
|
616
|
+
[■■■■■■■■■■] Epic 1 Big Bang ✓
|
|
617
|
+
[■■■■■■■■■■] Epic 2 PAL Router ✓
|
|
618
|
+
[■■■■■■■■■■] Epic 3 Double Diamond ✓
|
|
619
|
+
[■■■■■■■■■■] Epic 4 Resilience ✓
|
|
620
|
+
[■■■■■■■■■■] Epic 5 Evaluation ✓
|
|
621
|
+
[■■■■■■■■■■] Epic 6 Drift Control ✓
|
|
622
|
+
[■■■■■■■■■■] Epic 7 Secondary Loop ✓
|
|
623
|
+
[■■■■■■■■■■] Epic 8 Orchestrator ✓
|
|
624
|
+
[■■■■■■■■■■] Epic 9 MCP Integration ✓
|
|
625
|
+
[■■■■■■■■■■] Epic 10 TUI Mode ✓
|
|
580
626
|
```
|
|
581
627
|
|
|
628
|
+
### Upcoming
|
|
629
|
+
|
|
630
|
+
| Feature | Description | Status |
|
|
631
|
+
|---------|-------------|--------|
|
|
632
|
+
| **Worker MCP** | MCP server for distributed task execution | Planned |
|
|
633
|
+
| **TUI Enhancement** | Rich terminal UI with real-time progress | Planned |
|
|
634
|
+
| **AC Tree Visualization** | Interactive acceptance criteria graph | Planned |
|
|
635
|
+
| **Plugin System** | Custom evaluators and personas | Planned |
|
|
636
|
+
| **Web Dashboard** | Execution monitoring and analytics | Planned |
|
|
637
|
+
|
|
582
638
|
<br/>
|
|
583
639
|
|
|
584
640
|
---
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
ouroboros/__init__.py,sha256=
|
|
1
|
+
ouroboros/__init__.py,sha256=LhxtSCpFGoqFURoFs0JIc99GgkGvx6-kdLuyqcADqLU,701
|
|
2
2
|
ouroboros/__main__.py,sha256=f_qnL0zPJwh9kfQqynX5adpqzj8ilj94zW5Q2loqGxE,168
|
|
3
3
|
ouroboros/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
ouroboros/bigbang/__init__.py,sha256=
|
|
4
|
+
ouroboros/bigbang/__init__.py,sha256=lNYGEbPaeUB201jFPHsvJ-jIJC2XP-LtOyA32gVMb7o,1241
|
|
5
5
|
ouroboros/bigbang/ambiguity.py,sha256=5KM8xjATknjLZguVa90Yii6o3pzXE4PU4BJIP6Ii938,17955
|
|
6
|
-
ouroboros/bigbang/interview.py,sha256=
|
|
6
|
+
ouroboros/bigbang/interview.py,sha256=ku1MVppSmIS9OZeiqC208el4ZqoYYQwT78ycLenwID4,17200
|
|
7
|
+
ouroboros/bigbang/ontology.py,sha256=7sgNQav3KF7TBtw_25UflVc4QGQK29D-QY8eXgPMKBo,6145
|
|
7
8
|
ouroboros/bigbang/seed_generator.py,sha256=7MY9a7Eua_zVGDWIVDlzOZJjeAwz0DRatXJg0PvMgiY,20082
|
|
8
9
|
ouroboros/cli/__init__.py,sha256=CRpxsqJadZL7bCS-yrULWC51tqPKfPsxQLgt0JiwP4g,225
|
|
9
|
-
ouroboros/cli/main.py,sha256=
|
|
10
|
-
ouroboros/cli/commands/__init__.py,sha256=
|
|
10
|
+
ouroboros/cli/main.py,sha256=6TTrm9moBH5RCcJZ2xBNq4jrmI71p01PUqUZvJjSPfA,1525
|
|
11
|
+
ouroboros/cli/commands/__init__.py,sha256=Nc55qcwCsQm4vfA1UTAs6okTxKbGeqohJIkJi5689Uc,258
|
|
11
12
|
ouroboros/cli/commands/config.py,sha256=kcqi0Wo09oo1MMyZIX4k2IDICV1SAX6HzAXZaIJGdKY,2100
|
|
12
|
-
ouroboros/cli/commands/init.py,sha256=
|
|
13
|
-
ouroboros/cli/commands/
|
|
13
|
+
ouroboros/cli/commands/init.py,sha256=y2hlHnqFkc9-44_mJUs3GmQvX4Tg6yTIyb0e0KCPl30,16130
|
|
14
|
+
ouroboros/cli/commands/mcp.py,sha256=S-PkEyjwwQcdbrhrn4UUxjHCi-uBhfuy5gsDkyVjGZM,4343
|
|
15
|
+
ouroboros/cli/commands/run.py,sha256=MgwFlTorVsoz0Vk2m9x-g81flrYuWa2ZiJoNDpGIzqg,11014
|
|
14
16
|
ouroboros/cli/commands/status.py,sha256=Bnqpj1UkqhpBPYA11DV-Z63Bz8pjrebhlzeMKwz3_Ps,2217
|
|
15
17
|
ouroboros/cli/formatters/__init__.py,sha256=-Ik7KXajaIExBxSAp5iYp8gO9SfXudGjyDe2nm2_msw,691
|
|
16
18
|
ouroboros/cli/formatters/panels.py,sha256=d5TANIZy6FEEdpfnZaZ0epe-qIHJbh13qTCt23ur1jA,3388
|
|
@@ -23,13 +25,15 @@ ouroboros/core/__init__.py,sha256=VHGSB01i56Rncbx-vfKqpvZ1oXDJUu0xp0kQ6tuwRqw,16
|
|
|
23
25
|
ouroboros/core/ac_tree.py,sha256=GNyeWB3GVrQhYI83_g2ISYoviKnUf-U6vTY9p6xkklM,11949
|
|
24
26
|
ouroboros/core/context.py,sha256=A5WVPgsJlK-CDnDJx-_Tcfh_lE2AE3EYud45NKnYI2E,15675
|
|
25
27
|
ouroboros/core/errors.py,sha256=e4kiduueE3e2HvNyOJLnFRGFoue2vfW8JTerzxjp5TM,8057
|
|
28
|
+
ouroboros/core/ontology_aspect.py,sha256=j7nZbNGido18Qh2ECYSe1C33ZHP5S7O2G9zXQRi7HyI,14964
|
|
29
|
+
ouroboros/core/ontology_questions.py,sha256=R4VOe81J4Gx4ka6IF9XSqiyv6EahYpJhADzANH_GXU8,15133
|
|
26
30
|
ouroboros/core/security.py,sha256=LJq5FJzWdUIcjZGujI9xv1k3sFaD3XArBOlmArW-brg,9594
|
|
27
31
|
ouroboros/core/seed.py,sha256=OIO4p1evYqpIrt841LVDVMaBZq9RCkM-e78MOb94BS8,7114
|
|
28
32
|
ouroboros/core/types.py,sha256=SIc7XSIRizkeQU0kq4U02mZFsLtqVLmAo3ANypyUUfQ,6137
|
|
29
|
-
ouroboros/evaluation/__init__.py,sha256=
|
|
30
|
-
ouroboros/evaluation/consensus.py,sha256=
|
|
33
|
+
ouroboros/evaluation/__init__.py,sha256=LC1JHcewk_SBTjdwrrTQx3TiIcYC2qBxXBaCcxvgrWY,3461
|
|
34
|
+
ouroboros/evaluation/consensus.py,sha256=Z5XSQw5W9H3DHLbLUZMVXfSvSi87DRfhoVidhdASOuQ,29394
|
|
31
35
|
ouroboros/evaluation/mechanical.py,sha256=gWvCUaR8Ibmpnrl9gjv0LYhwC5MgJ65gyTFcjzHqLZc,11285
|
|
32
|
-
ouroboros/evaluation/models.py,sha256=
|
|
36
|
+
ouroboros/evaluation/models.py,sha256=IrnmV_gueO2gGtS73pNRVCMiS06oiMju33raP1N4LMo,10062
|
|
33
37
|
ouroboros/evaluation/pipeline.py,sha256=k4gQzkKxzMvqKpMxK4bAVAm-Ux06RYjlwNOCDD5EvQI,10056
|
|
34
38
|
ouroboros/evaluation/semantic.py,sha256=qSKrYHMzt8DLygULH5xI2Sy_pXfis9-_bIjjziUf3kI,9406
|
|
35
39
|
ouroboros/evaluation/trigger.py,sha256=yNQZrVAP8L6KOKNDQNqeCxDqxbYIZY8b7w-lBSMlL5A,9695
|
|
@@ -37,19 +41,38 @@ ouroboros/events/__init__.py,sha256=LIvrE41r1eGo6Qb1-mOfoyVAcZ3hObS4o7Jq3sCnVPU,
|
|
|
37
41
|
ouroboros/events/base.py,sha256=y4ZIqs_HK66GRVZz7HZ02pkQ8lS2NxIkJFOB3frm8y0,2627
|
|
38
42
|
ouroboros/events/decomposition.py,sha256=rA2E4SLB5UgEZMXzGPFVO75r1D96PWQ8PnBBJKug3nE,4357
|
|
39
43
|
ouroboros/events/evaluation.py,sha256=HfQ6xu5JLV5tIjL-NxsXykDIvKmjBSrLr1tQHcr4aAI,6922
|
|
44
|
+
ouroboros/events/ontology.py,sha256=XRj788ekkLpDNIvvo163JfbaP8jrhTKfqtw9kriGd6s,3855
|
|
40
45
|
ouroboros/execution/__init__.py,sha256=nG9f51vi1O3zLGusbZfOqZebvUgMxm9R7JjoUDPGC1E,1101
|
|
41
46
|
ouroboros/execution/atomicity.py,sha256=JacsYaUhm9r05R8sMBoJRDnTmba4jpMXQU6SvQIuAzM,13988
|
|
42
47
|
ouroboros/execution/decomposition.py,sha256=NWTVuQoLw4vzMMGNdtCv-i5olOGIZADd2ogdFURzssU,14682
|
|
43
48
|
ouroboros/execution/double_diamond.py,sha256=lbk9cY3Awd0h_YFp1G5OJnDpkV8htanSDhQIYn0LA_8,49837
|
|
44
49
|
ouroboros/execution/subagent.py,sha256=_0-Ayz1p4r-cJP6kAYQP-bf9g2yLKXV81wffurBK9YM,8727
|
|
50
|
+
ouroboros/mcp/__init__.py,sha256=C3vtzrnNcxjsnelhCiDpYHjMl8EoER-Ojx4K5q5mfr4,2071
|
|
51
|
+
ouroboros/mcp/errors.py,sha256=dzk6E1iQE8Lyc3zd_0Xpm3wQzmAzyCPPcyswpvx_VQ4,11585
|
|
52
|
+
ouroboros/mcp/types.py,sha256=uQEtzhFn5sNyoHhXLE4D4u35A3Gd-NpMkzMPEcnT47M,9081
|
|
53
|
+
ouroboros/mcp/client/__init__.py,sha256=o0vDlamaRLQLrjsZfd9gthTD-iuknuJnbCxlgfKWM5Y,603
|
|
54
|
+
ouroboros/mcp/client/adapter.py,sha256=_tGxM71IRCwWN3-qvQuW6K9GbpPkXNjVV60CrIN28OE,21629
|
|
55
|
+
ouroboros/mcp/client/manager.py,sha256=0z0U9LlUez6hJRfBn-PYo1yAU5T1wILpeqluOoZF2AM,20294
|
|
56
|
+
ouroboros/mcp/client/protocol.py,sha256=GEK0zoPo10r4M2TwwQ6LjT_eadvBwF1sa8UnZZIlXWs,4809
|
|
57
|
+
ouroboros/mcp/resources/__init__.py,sha256=o7EJL9XEJYXy1-aqAnavuYVkTHeHH_hrg_TcEbeni58,467
|
|
58
|
+
ouroboros/mcp/resources/handlers.py,sha256=kq8ks8hiOlwDlFC-H1u9Xmjf9mE155PHRS7LsoYjhMQ,10851
|
|
59
|
+
ouroboros/mcp/server/__init__.py,sha256=Tb7SATt1rHnuVLfMCTwEJIf9R3CkeCc-POqZ3xZvWP0,598
|
|
60
|
+
ouroboros/mcp/server/adapter.py,sha256=jyxoKw9gjUI_QQoXJ81mROttxKWHD7tBbXyrShexmJ8,13128
|
|
61
|
+
ouroboros/mcp/server/protocol.py,sha256=ZCYeWwDXeRdktUtP-mX0AktnypMVTbYFm8uTwsJIu6w,8120
|
|
62
|
+
ouroboros/mcp/server/security.py,sha256=IUf21iSbF7C4IBC5_1hfYnTi0mfLl-wgiFWQR7WK4uk,20017
|
|
63
|
+
ouroboros/mcp/tools/__init__.py,sha256=eigHzFsdKtRrJAYbmLVra3csRBqpL1UNQqc0l-Zz8D8,566
|
|
64
|
+
ouroboros/mcp/tools/definitions.py,sha256=saOE_Wz1B9pHQUma4KEDH2uXJtR0-DmnSJc52n_NIyk,11509
|
|
65
|
+
ouroboros/mcp/tools/registry.py,sha256=_tETlbheZYQr03X3YxzsMn0jxz7CpIQ4dl4LP66RcbI,7482
|
|
45
66
|
ouroboros/observability/__init__.py,sha256=jgLIxPgBPJgSLCUjxR28tO3gkOuknbnb0H87NwkCl6Q,1654
|
|
46
67
|
ouroboros/observability/drift.py,sha256=1BxZq-XIfhOJpTiBzbqgMpxziiJsb9KcLg_F5QKBIeM,11361
|
|
47
68
|
ouroboros/observability/logging.py,sha256=MC_VzyAyJtTq_3iv7uLxvlO9eCxtdY2ZyJ7ObwDds98,16994
|
|
48
69
|
ouroboros/observability/retrospective.py,sha256=FH_9UC20RnH7OHNXMVIbsqC74B_4KIUy0UjtK-rguXU,11177
|
|
49
|
-
ouroboros/orchestrator/__init__.py,sha256=
|
|
70
|
+
ouroboros/orchestrator/__init__.py,sha256=JAapdYn03B1Fqpz4atJMGfp612uEDMTJ91swD4OGq2A,3005
|
|
50
71
|
ouroboros/orchestrator/adapter.py,sha256=TpvgVMNfvNqvuffn41JDMYjWt2MFCLqTW1MtwOEZ-6E,13152
|
|
51
|
-
ouroboros/orchestrator/events.py,sha256=
|
|
52
|
-
ouroboros/orchestrator/
|
|
72
|
+
ouroboros/orchestrator/events.py,sha256=BuY6N6uXBAN8fWdlnHT2EfpztnzIa4HyBgk98su0BgQ,8756
|
|
73
|
+
ouroboros/orchestrator/mcp_config.py,sha256=FZvEfQmlC9qnvj18bWnL8XFFN8ROYQmrAb5tkEs9fj4,12293
|
|
74
|
+
ouroboros/orchestrator/mcp_tools.py,sha256=MvHbjRmgqG9S0T3ZMgFm6tofeUNM7n7Ny8CAaaL9ZJ0,15418
|
|
75
|
+
ouroboros/orchestrator/runner.py,sha256=zGKWQrPkTGXK0fluVhlJb7B9KYflxQyfODuV6RXnAKs,24668
|
|
53
76
|
ouroboros/orchestrator/session.py,sha256=JWfQfwwlf7_f80l9Ed45zQA6iDb32XoOnaYbGjA6ChU,15536
|
|
54
77
|
ouroboros/persistence/__init__.py,sha256=O9lVtKUNgtpamzo-OAeEVYXByqpy83853DKepvo3Zj8,601
|
|
55
78
|
ouroboros/persistence/checkpoint.py,sha256=FC68lOmNcRJooFEYXGrGWR0TZcQG-YA9qvPPnl4QMUc,17580
|
|
@@ -61,7 +84,7 @@ ouroboros/persistence/migrations/runner.py,sha256=FPlnmjT0U-wTDRdHHImM6wMzEzMAGX
|
|
|
61
84
|
ouroboros/persistence/migrations/scripts/001_initial.sql,sha256=ZkABj9VKEyvwYwCmnT7PZt8bODMKUw4oThnuhHdxHwg,848
|
|
62
85
|
ouroboros/providers/__init__.py,sha256=sFQ049Gizx2GxWUTlsCLZHaskV8NVwPDdkXiLEWhrbc,583
|
|
63
86
|
ouroboros/providers/base.py,sha256=u86bWAXtNIVCL1SxqXFK9sqpL6SZOc9h2vxAuVh7mxo,3823
|
|
64
|
-
ouroboros/providers/claude_code_adapter.py,sha256=
|
|
87
|
+
ouroboros/providers/claude_code_adapter.py,sha256=72Evb__QZMCg9_E1C5duk1e1hPfh_6F0mAAQiWoXNzI,9990
|
|
65
88
|
ouroboros/providers/litellm_adapter.py,sha256=ljl1SywN1QXEy6LrLhsUYvh9qc0RUuKIG8XFCRtU4yg,10761
|
|
66
89
|
ouroboros/resilience/__init__.py,sha256=jcMdyk5WwaIh7iFVQ5rwaexCnnVpnumJUgWf4GO6w_4,1980
|
|
67
90
|
ouroboros/resilience/lateral.py,sha256=Z4B7pOrD93D6bXu8BqrUvibqYSGyjv8Ubp6nWfLipjM,21582
|
|
@@ -75,8 +98,10 @@ ouroboros/routing/tiers.py,sha256=QhBQUOo2-h5Z3dEtC0lcOzkRnqTi2W7Jl46750AVNig,73
|
|
|
75
98
|
ouroboros/secondary/__init__.py,sha256=kYQ7C4bnBzwDlPrU8qZrOPr2ZuTBaftGktOXl5WZl5Q,1123
|
|
76
99
|
ouroboros/secondary/scheduler.py,sha256=sPVVWJ1q0yewRAM-Rm1j_HMerSe4cavIvP9z4xlUuL4,13737
|
|
77
100
|
ouroboros/secondary/todo_registry.py,sha256=4W3C9Uro29VrVLCPKUlpH_BYpzQSbRNW1oMnDYyEhEw,13880
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
ouroboros_ai-0.
|
|
81
|
-
ouroboros_ai-0.
|
|
82
|
-
ouroboros_ai-0.
|
|
101
|
+
ouroboros/strategies/__init__.py,sha256=OuSimhS6q37e_D6F5Lb1ZahXTLkYZBfcUUAxspPSorw,623
|
|
102
|
+
ouroboros/strategies/devil_advocate.py,sha256=i32pseJDc44klb4Vr-gQfPBdZvMHCJhobb2wR7VSeG4,6289
|
|
103
|
+
ouroboros_ai-0.4.0.dist-info/METADATA,sha256=3cFNN3hEAL5Y_MB1NXd1NA9qZ9NbXLA6M2cimeZUCMs,21645
|
|
104
|
+
ouroboros_ai-0.4.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
105
|
+
ouroboros_ai-0.4.0.dist-info/entry_points.txt,sha256=MoETHup6rVkR6AsyjoRzAgIuvVtYYm3Jw40itV3_VyI,53
|
|
106
|
+
ouroboros_ai-0.4.0.dist-info/licenses/LICENSE,sha256=n2X-q26TqpXnoBo0t_WouhFxWw663_q5FmbYDZayoHo,1060
|
|
107
|
+
ouroboros_ai-0.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|