agentic-fabric 1.2.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.
Files changed (45) hide show
  1. agentic_fabric/__init__.py +90 -0
  2. agentic_fabric/__main__.py +9 -0
  3. agentic_fabric/agentic_data.py +284 -0
  4. agentic_fabric/base/__init__.py +150 -0
  5. agentic_fabric/base/archetypes.yaml +75 -0
  6. agentic_fabric/capabilities.py +130 -0
  7. agentic_fabric/config/__init__.py +10 -0
  8. agentic_fabric/config/agents.yaml +101 -0
  9. agentic_fabric/config/llm.py +285 -0
  10. agentic_fabric/config/tasks.yaml +177 -0
  11. agentic_fabric/core/__init__.py +17 -0
  12. agentic_fabric/core/decomposer.py +278 -0
  13. agentic_fabric/core/discovery.py +359 -0
  14. agentic_fabric/core/loader.py +207 -0
  15. agentic_fabric/core/manager.py +296 -0
  16. agentic_fabric/core/runner.py +70 -0
  17. agentic_fabric/fabric_agents/__init__.py +1 -0
  18. agentic_fabric/fabric_agents/connector_builder/__init__.py +1 -0
  19. agentic_fabric/fabric_agents/connector_builder/config/agents.yaml +16 -0
  20. agentic_fabric/fabric_agents/connector_builder/config/tasks.yaml +14 -0
  21. agentic_fabric/fabric_agents/connector_builder/connector_builder_fabric.py +103 -0
  22. agentic_fabric/main.py +591 -0
  23. agentic_fabric/runners/__init__.py +32 -0
  24. agentic_fabric/runners/base.py +369 -0
  25. agentic_fabric/runners/crewai_runner.py +206 -0
  26. agentic_fabric/runners/langgraph_runner.py +199 -0
  27. agentic_fabric/runners/local_cli_profiles.yaml +169 -0
  28. agentic_fabric/runners/local_cli_runner.py +491 -0
  29. agentic_fabric/runners/registry.py +165 -0
  30. agentic_fabric/runners/single_agent_runner.py +77 -0
  31. agentic_fabric/runners/strands_runner.py +214 -0
  32. agentic_fabric/tools/__init__.py +76 -0
  33. agentic_fabric/tools/adapters.py +128 -0
  34. agentic_fabric/tools/file_tools.py +391 -0
  35. agentic_fabric/tools/meshy_mcp.py +214 -0
  36. agentic_fabric/tools/registry.py +169 -0
  37. agentic_fabric/tools/scraping_tools.py +148 -0
  38. agentic_fabric/tools/vendor.py +110 -0
  39. agentic_fabric/tools/vendor_mcp.py +338 -0
  40. agentic_fabric/utils/__init__.py +6 -0
  41. agentic_fabric/utils/files.py +25 -0
  42. agentic_fabric-1.2.0.dist-info/METADATA +292 -0
  43. agentic_fabric-1.2.0.dist-info/RECORD +45 -0
  44. agentic_fabric-1.2.0.dist-info/WHEEL +4 -0
  45. agentic_fabric-1.2.0.dist-info/entry_points.txt +4 -0
@@ -0,0 +1,90 @@
1
+ """agentic-fabric: Framework-agnostic AI fabric orchestration.
2
+
3
+ Declare fabric agents once, run on CrewAI, LangGraph, or Strands.
4
+
5
+ Usage:
6
+ from agentic_fabric.core.decomposer import run_fabric_agent_auto, get_runner, detect_framework
7
+ from agentic_fabric.core.discovery import discover_packages, get_fabric_agent_config
8
+ from agentic_fabric.core.manager import ManagerAgent
9
+
10
+ # Auto-detect framework and run a fabric agent
11
+ packages = discover_packages()
12
+ config = get_fabric_agent_config(packages["my-package"], "reviewer")
13
+ result = run_fabric_agent_auto(config, inputs={"task": "..."})
14
+
15
+ # Or get a specific runner
16
+ runner = get_runner("crewai") # or "langgraph", "strands"
17
+ fabric_agent = runner.build_fabric_agent(config)
18
+ result = runner.run(fabric_agent, inputs)
19
+
20
+ # Or use a hierarchical manager agent
21
+ class MyManager(ManagerAgent):
22
+ def __init__(self):
23
+ super().__init__(fabric_agents={
24
+ "design": "design_review",
25
+ "implementation": "implementation_review"
26
+ })
27
+
28
+ async def execute_workflow(self, task):
29
+ design = await self.delegate_async("design", task)
30
+ return await self.delegate_async("implementation", design)
31
+ """
32
+
33
+ from __future__ import annotations
34
+
35
+ from importlib.metadata import PackageNotFoundError, version
36
+
37
+
38
+ try:
39
+ __version__ = version("agentic-fabric")
40
+ except PackageNotFoundError: # pragma: no cover - only hit when not installed
41
+ __version__ = "1.2.0"
42
+
43
+ # Core exports - framework-agnostic functionality
44
+ from agentic_fabric.agentic_data import AgenticData
45
+ from agentic_fabric.capabilities import (
46
+ AgentCapabilityProviderMixin,
47
+ AgentCapabilitySpec,
48
+ agent_capability,
49
+ runtime_capability,
50
+ tool_capability,
51
+ )
52
+ from agentic_fabric.core.decomposer import (
53
+ compose_fabric_agent,
54
+ detect_framework,
55
+ get_available_frameworks,
56
+ get_framework_info,
57
+ get_runner,
58
+ is_framework_available,
59
+ run_fabric_agent_auto,
60
+ )
61
+ from agentic_fabric.core.discovery import (
62
+ discover_all_framework_configs,
63
+ discover_packages,
64
+ get_fabric_agent_config,
65
+ list_fabric_agents,
66
+ )
67
+ from agentic_fabric.core.manager import ManagerAgent
68
+
69
+
70
+ __all__ = [
71
+ "AgentCapabilityProviderMixin",
72
+ "AgentCapabilitySpec",
73
+ "AgenticData",
74
+ "ManagerAgent",
75
+ "__version__",
76
+ "agent_capability",
77
+ "compose_fabric_agent",
78
+ "detect_framework",
79
+ "discover_all_framework_configs",
80
+ "discover_packages",
81
+ "get_available_frameworks",
82
+ "get_fabric_agent_config",
83
+ "get_framework_info",
84
+ "get_runner",
85
+ "is_framework_available",
86
+ "list_fabric_agents",
87
+ "run_fabric_agent_auto",
88
+ "runtime_capability",
89
+ "tool_capability",
90
+ ]
@@ -0,0 +1,9 @@
1
+ """Allow running as: python -m agentic_fabric."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from agentic_fabric.main import main
6
+
7
+
8
+ if __name__ == "__main__":
9
+ main()
@@ -0,0 +1,284 @@
1
+ """Agent runtime facade over the vendor and data layers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Mapping
6
+ from types import MappingProxyType
7
+ from typing import Any, ClassVar
8
+
9
+ from agentic_fabric.runners.registry import RuntimeUnavailableError, install_command, runtime_info, runtime_names
10
+
11
+
12
+ try: # pragma: no cover - exercised when vendor-fabric is installed by consumers
13
+ from vendor_fabric.vendor_data import VendorData as _VendorDataBase
14
+ except ImportError: # pragma: no cover - default in this workspace until vendor-fabric is published
15
+ _VENDOR_FABRIC_AVAILABLE = False
16
+
17
+ class _VendorDataBase: # type: ignore[no-redef]
18
+ """Small fallback that keeps AgenticData importable without vendor-fabric.
19
+
20
+ This is an importability shim, not a second architecture. It implements
21
+ the minimal ``VendorData`` surface needed for ``AgenticData`` to function.
22
+ Methods that require vendor-fabric raise clear ``ImportError`` guidance.
23
+
24
+ Omitted vs. real ``VendorData``: ``capabilities()`` returns an empty list
25
+ (so ``vendor_tools()`` degrades gracefully instead of crashing).
26
+ """
27
+
28
+ def __init__(self, value: Any = None, *, fabric: Any = None, logger: Any = None, **_: Any) -> None:
29
+ self._agentic_value = value
30
+ self._active_provider: str | None = None
31
+ self._logger = logger
32
+
33
+ @property
34
+ def value(self) -> Any:
35
+ """Return the wrapped value."""
36
+ return self._agentic_value
37
+
38
+ @property
39
+ def active_provider(self) -> str | None:
40
+ """Return the active vendor provider, when available."""
41
+ return self._active_provider
42
+
43
+ def as_builtin(self) -> Any:
44
+ """Return the wrapped value unchanged."""
45
+ return self._agentic_value
46
+
47
+ def cast(self, value: Any) -> _VendorDataBase:
48
+ """Replace the wrapped value."""
49
+ self._agentic_value = value
50
+ return self
51
+
52
+ def open(self, provider_id: str, *, strict: bool = True, **_: Any) -> _VendorDataBase:
53
+ """Record a provider or raise install guidance when strict."""
54
+ if strict:
55
+ msg = (
56
+ f"Provider '{provider_id}' requires vendor-fabric. "
57
+ "Install vendor-fabric after it is published, then reinstall agentic-fabric."
58
+ )
59
+ raise ImportError(msg)
60
+ self._active_provider = provider_id
61
+ return self
62
+
63
+ def call(self, operation: str, *_: Any, **__: Any) -> Any:
64
+ """Raise clear guidance for vendor-backed operations."""
65
+ msg = f"Vendor operation '{operation}' requires vendor-fabric."
66
+ raise ImportError(msg)
67
+
68
+ def capabilities(self, provider: str | None = None, *, include_unavailable: bool = True) -> list[Any]:
69
+ """Return an empty capability list without vendor-fabric.
70
+
71
+ Without vendor-fabric, no provider capabilities are available.
72
+ This lets ``vendor_tools()`` degrade gracefully (returns ``[]``).
73
+ """
74
+ return []
75
+
76
+ else:
77
+ _VENDOR_FABRIC_AVAILABLE = True
78
+
79
+
80
+ class AgenticData(_VendorDataBase):
81
+ """VendorData extension with active runtime and fabric agent registry context."""
82
+
83
+ runtime_priority: ClassVar[tuple[str, ...]] = tuple(runtime_names())
84
+
85
+ def __init__(
86
+ self,
87
+ value: Any = None,
88
+ *,
89
+ fabric: Any | None = None,
90
+ fabric_agents: Mapping[str, Mapping[str, Any]] | None = None,
91
+ logger: Any | None = None,
92
+ active_runtime: str | None = None,
93
+ **fabric_kwargs: Any,
94
+ ) -> None:
95
+ """Initialize data, registered fabric agents, and optional active runtime."""
96
+ super().__init__(value, fabric=fabric, logger=logger, **fabric_kwargs)
97
+ self._fabric_agents: dict[str, dict[str, Any]] = {
98
+ name: dict(config) for name, config in (fabric_agents or {}).items()
99
+ }
100
+ self._active_runtime: str | None = None
101
+ if active_runtime is not None:
102
+ self.use_runtime(active_runtime, strict=False)
103
+
104
+ @property
105
+ def fabric_agents(self) -> Mapping[str, Mapping[str, Any]]:
106
+ """Return registered fabric agent definitions."""
107
+ return MappingProxyType(self._fabric_agents)
108
+
109
+ @property
110
+ def active_runtime(self) -> str | None:
111
+ """Return the active runtime name, when one has been selected."""
112
+ return self._active_runtime
113
+
114
+ @property
115
+ def vendor_fabric_available(self) -> bool:
116
+ """Return whether this import is backed by a real VendorData class."""
117
+ return _VENDOR_FABRIC_AVAILABLE
118
+
119
+ def cast(self, value: Any) -> AgenticData:
120
+ """Mutate the wrapped data while preserving runtime context."""
121
+ super().cast(value)
122
+ return self
123
+
124
+ def register_fabric_agent(self, name: str, fabric_agent_config: Mapping[str, Any]) -> AgenticData:
125
+ """Register a named fabric agent config for ``run_fabric_agent`` lookup."""
126
+ self._fabric_agents[name] = dict(fabric_agent_config)
127
+ return self
128
+
129
+ def unregister_fabric_agent(self, name: str) -> AgenticData:
130
+ """Remove a named fabric agent config if it exists."""
131
+ self._fabric_agents.pop(name, None)
132
+ return self
133
+
134
+ def use_runtime(self, runtime: str, *, strict: bool = True) -> AgenticData:
135
+ """Select the active runtime for future agent calls."""
136
+ normalized = runtime.strip().lower()
137
+ if normalized == "auto":
138
+ normalized = self.select_runtime()
139
+ if strict and not self.is_runtime_available(normalized):
140
+ raise RuntimeUnavailableError(normalized, install_command(normalized))
141
+ self._active_runtime = normalized
142
+ return self
143
+
144
+ def clear_runtime(self) -> AgenticData:
145
+ """Clear the active runtime selection."""
146
+ self._active_runtime = None
147
+ return self
148
+
149
+ def runtimes(self) -> list[dict[str, Any]]:
150
+ """Return runtime registry metadata with availability."""
151
+ info = runtime_info()
152
+ return list(info) if isinstance(info, list) else [info]
153
+
154
+ def runtime_info(self, runtime: str | None = None) -> list[dict[str, Any]] | dict[str, Any]:
155
+ """Return runtime metadata with current availability."""
156
+ return runtime_info(runtime)
157
+
158
+ def is_runtime_available(self, runtime: str) -> bool:
159
+ """Return whether a runtime is importable in the current environment."""
160
+ from agentic_fabric.core.decomposer import is_framework_available
161
+
162
+ return is_framework_available(runtime)
163
+
164
+ def select_runtime(
165
+ self,
166
+ runtime: str | None = None,
167
+ *,
168
+ fabric_agent_config: Mapping[str, Any] | None = None,
169
+ ) -> str:
170
+ """Select a runtime using explicit, active, manifest, then auto priority."""
171
+ required_runtime = _manifest_runtime(fabric_agent_config)
172
+ requested = _normalize_runtime(runtime)
173
+ active = _normalize_runtime(self._active_runtime)
174
+
175
+ if requested is not None and required_runtime is not None and requested != required_runtime:
176
+ msg = f"Fabric agent requires {required_runtime} but {requested} was requested"
177
+ raise ValueError(msg)
178
+
179
+ if requested is not None:
180
+ return _require_available(requested)
181
+
182
+ if active is not None:
183
+ if required_runtime is not None and active != required_runtime:
184
+ msg = f"Active runtime {active} conflicts with fabric agent requirement {required_runtime}"
185
+ raise ValueError(msg)
186
+ return _require_available(active)
187
+
188
+ if required_runtime is not None:
189
+ return _require_available(required_runtime)
190
+
191
+ from agentic_fabric.core.decomposer import detect_framework
192
+
193
+ return detect_framework()
194
+
195
+ def run_fabric_agent(
196
+ self,
197
+ fabric_agent: str | Mapping[str, Any],
198
+ inputs: Mapping[str, Any] | None = None,
199
+ *,
200
+ runtime: str | None = None,
201
+ **input_kwargs: Any,
202
+ ) -> str:
203
+ """Run a registered fabric agent by name or a direct fabric agent config."""
204
+ from agentic_fabric.core.decomposer import run_fabric_agent_auto
205
+
206
+ fabric_agent_config = self._lookup_fabric_agent(fabric_agent)
207
+ merged_inputs = dict(inputs or {})
208
+ merged_inputs.update(input_kwargs)
209
+ selected_runtime = self.select_runtime(runtime, fabric_agent_config=fabric_agent_config)
210
+ return run_fabric_agent_auto(fabric_agent_config, inputs=merged_inputs, framework=selected_runtime)
211
+
212
+ def call_runtime(self, capability: str, *args: Any, runtime: str | None = None, **kwargs: Any) -> Any:
213
+ """Call a declared capability on a selected runtime runner."""
214
+ from agentic_fabric.core.decomposer import get_runner
215
+
216
+ selected_runtime = self.select_runtime(runtime)
217
+ runner = get_runner(selected_runtime)
218
+ return runner.call_capability(capability, *args, **kwargs)
219
+
220
+ def vendor_tools(
221
+ self,
222
+ provider: str | None = None,
223
+ *,
224
+ include_unavailable: bool = True,
225
+ ) -> list[Any]:
226
+ """Return agent-facing tools built from inherited vendor capabilities."""
227
+ from agentic_fabric.tools.vendor import vendor_capability_tools
228
+
229
+ return vendor_capability_tools(self, provider=provider, include_unavailable=include_unavailable)
230
+
231
+ def __getattr__(self, name: str) -> Any:
232
+ """Expose ``run_<fabric_agent>`` helpers while preserving VendorData dispatch."""
233
+ if name.startswith("run_"):
234
+ fabric_agent_name = name.removeprefix("run_")
235
+ if fabric_agent_name in self._fabric_agents:
236
+ return lambda *args, **kwargs: self.run_fabric_agent(fabric_agent_name, *args, **kwargs)
237
+
238
+ # When real VendorData is installed, it may define __getattr__ for
239
+ # provider dispatch. Try the superclass, but fall through to a clean
240
+ # AttributeError if neither this class nor the superclass handles it.
241
+ if hasattr(super(), "__getattr__"):
242
+ return super().__getattr__(name) # type: ignore[misc]
243
+ raise AttributeError(f"{type(self).__name__!s} has no attribute {name!r}")
244
+
245
+ def __dir__(self) -> list[str]:
246
+ """Include dynamic registered-fabric-agent helpers in introspection."""
247
+ dynamic = [f"run_{name}" for name in self._fabric_agents]
248
+ return sorted({*super().__dir__(), *dynamic})
249
+
250
+ def _lookup_fabric_agent(self, fabric_agent: str | Mapping[str, Any]) -> dict[str, Any]:
251
+ """Return a fabric agent config from a name or direct mapping."""
252
+ if isinstance(fabric_agent, Mapping):
253
+ return dict(fabric_agent)
254
+ try:
255
+ return dict(self._fabric_agents[fabric_agent])
256
+ except KeyError as exc:
257
+ options = ", ".join(sorted(self._fabric_agents)) or "none registered"
258
+ msg = f"Unknown fabric agent '{fabric_agent}'. Registered fabric agents: {options}"
259
+ raise KeyError(msg) from exc
260
+
261
+
262
+ def _normalize_runtime(runtime: str | None) -> str | None:
263
+ """Normalize runtime names and treat auto as no explicit choice."""
264
+ if runtime is None:
265
+ return None
266
+ normalized = runtime.strip().lower()
267
+ return None if normalized == "auto" else normalized
268
+
269
+
270
+ def _manifest_runtime(fabric_agent_config: Mapping[str, Any] | None) -> str | None:
271
+ """Read runtime requirements from a fabric agent manifest/config mapping."""
272
+ if fabric_agent_config is None:
273
+ return None
274
+ runtime = fabric_agent_config.get("required_framework") or fabric_agent_config.get("runtime") or fabric_agent_config.get("framework")
275
+ return _normalize_runtime(str(runtime)) if runtime else None
276
+
277
+
278
+ def _require_available(runtime: str) -> str:
279
+ """Return a runtime or raise install guidance."""
280
+ from agentic_fabric.core.decomposer import is_framework_available
281
+
282
+ if not is_framework_available(runtime):
283
+ raise RuntimeUnavailableError(runtime, install_command(runtime))
284
+ return runtime
@@ -0,0 +1,150 @@
1
+ """Base module - reusable agent archetypes and shared tool re-exports.
2
+
3
+ Archetypes are base templates that packages can extend in their own
4
+ ``agents.yaml``. Use the ``extends`` field to inherit from an archetype:
5
+
6
+ .. code:: yaml
7
+
8
+ my_engineer:
9
+ extends: senior_engineer
10
+ variables:
11
+ language: Python
12
+ backstory: |
13
+ {base}
14
+ Additional context specific to my package...
15
+
16
+ The ``{base}`` placeholder in agent config is replaced with the
17
+ archetype's value. ``{language}`` and other ``variables`` are interpolated
18
+ into the resolved role/goal/backstory strings.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import logging
24
+
25
+ from pathlib import Path
26
+ from typing import Any
27
+
28
+ import yaml
29
+
30
+ from agentic_fabric.tools.file_tools import (
31
+ DirectoryListTool,
32
+ GameCodeReaderTool,
33
+ GameCodeWriterTool,
34
+ )
35
+
36
+
37
+ logger = logging.getLogger(__name__)
38
+
39
+ _ARCHETYPES_PATH = Path(__file__).parent / "archetypes.yaml"
40
+
41
+
42
+ def _load_archetypes() -> dict[str, dict[str, Any]]:
43
+ """Load built-in archetypes from the bundled YAML file."""
44
+ try:
45
+ data = yaml.safe_load(_ARCHETYPES_PATH.read_text(encoding="utf-8"))
46
+ except OSError as exc:
47
+ logger.warning("Could not load archetypes.yaml: %s", exc)
48
+ return {}
49
+ if not isinstance(data, dict):
50
+ return {}
51
+ return data.get("archetypes", {})
52
+
53
+
54
+ def _interpolate(text: str, variables: dict[str, Any]) -> str:
55
+ """Interpolate ``{key}`` placeholders in *text* using *variables*."""
56
+ if not text:
57
+ return text
58
+ try:
59
+ return text.format(**variables)
60
+ except (KeyError, IndexError, ValueError):
61
+ return text
62
+
63
+
64
+ def resolve_archetype(
65
+ agent_config: dict[str, Any],
66
+ *,
67
+ archetypes: dict[str, dict[str, Any]] | None = None,
68
+ ) -> dict[str, Any]:
69
+ """Resolve ``extends`` and ``variables`` in an agent config.
70
+
71
+ If the config has an ``extends`` key, the named archetype is loaded
72
+ and its role/goal/backstory are merged. ``{base}`` in the agent's
73
+ own field is replaced with the archetype's value. Other ``{variables}``
74
+ are interpolated into the final resolved strings.
75
+
76
+ Args:
77
+ agent_config: Raw agent config dict that may contain ``extends``
78
+ and ``variables``.
79
+ archetypes: Optional pre-loaded archetypes dict. If ``None``,
80
+ built-in archetypes are loaded from ``archetypes.yaml``.
81
+
82
+ Returns:
83
+ New config dict with ``extends`` and ``variables`` consumed
84
+ and all string fields interpolated.
85
+ """
86
+ extends = agent_config.get("extends")
87
+ if not extends:
88
+ return dict(agent_config)
89
+
90
+ if archetypes is None:
91
+ archetypes = _load_archetypes()
92
+
93
+ archetype = archetypes.get(extends)
94
+ if archetype is None:
95
+ logger.warning("Agent config extends unknown archetype '%s'", extends)
96
+ result = dict(agent_config)
97
+ result.pop("extends", None)
98
+ result.pop("variables", None)
99
+ return result
100
+
101
+ variables = agent_config.get("variables", {})
102
+ if not isinstance(variables, dict):
103
+ variables = {}
104
+
105
+ resolved: dict[str, Any] = dict(agent_config)
106
+ resolved.pop("extends", None)
107
+ resolved.pop("variables", None)
108
+
109
+ for field in ("role", "goal", "backstory"):
110
+ agent_value = agent_config.get(field, "")
111
+ archetype_value = archetype.get(field, "")
112
+ # {base} in the agent's value is replaced with the archetype value
113
+ merged = agent_value.replace("{base}", archetype_value) if agent_value else archetype_value
114
+ resolved[field] = _interpolate(merged, variables)
115
+
116
+ # Copy any fields from the archetype not overridden by the agent
117
+ for key, value in archetype.items():
118
+ if key not in resolved:
119
+ resolved[key] = value
120
+
121
+ return resolved
122
+
123
+
124
+ def resolve_agent_archetypes(
125
+ agents_config: dict[str, dict[str, Any]],
126
+ *,
127
+ archetypes: dict[str, dict[str, Any]] | None = None,
128
+ ) -> dict[str, dict[str, Any]]:
129
+ """Resolve archetypes for every agent in a config dict.
130
+
131
+ Args:
132
+ agents_config: Dict mapping agent names to agent configs.
133
+ archetypes: Optional pre-loaded archetypes dict.
134
+
135
+ Returns:
136
+ New dict with archetypes resolved for each agent.
137
+ """
138
+ return {
139
+ name: resolve_archetype(config, archetypes=archetypes)
140
+ for name, config in agents_config.items()
141
+ }
142
+
143
+
144
+ __all__ = [
145
+ "DirectoryListTool",
146
+ "GameCodeReaderTool",
147
+ "GameCodeWriterTool",
148
+ "resolve_agent_archetypes",
149
+ "resolve_archetype",
150
+ ]
@@ -0,0 +1,75 @@
1
+ # Reusable Agent Archetypes
2
+ #
3
+ # These are base templates that packages can extend in their own agents.yaml.
4
+ # Use the 'extends' field to inherit from an archetype.
5
+ #
6
+ # Example usage in packages/mypackage/.fabric/fabric_agents/builder/agents.yaml:
7
+ # my_engineer:
8
+ # extends: senior_engineer
9
+ # variables:
10
+ # language: Python
11
+ # backstory: |
12
+ # {base}
13
+ # Additional context specific to my package...
14
+
15
+ archetypes:
16
+ senior_engineer:
17
+ role: "Senior {language} Engineer"
18
+ goal: >
19
+ Write production-quality {language} code following best practices
20
+ and existing patterns in the codebase.
21
+ backstory: >
22
+ You are a senior developer with 10+ years of experience.
23
+ You always read existing code before writing new code.
24
+ You follow project conventions exactly.
25
+ You write clean, well-documented code with proper types.
26
+
27
+ qa_engineer:
28
+ role: "Quality Assurance Engineer"
29
+ goal: >
30
+ Review code for errors, security issues, type safety problems,
31
+ and deviations from project conventions.
32
+ backstory: >
33
+ You specialize in code review with an eye for:
34
+ - Type safety and proper interface usage
35
+ - Missing imports that would cause errors
36
+ - Inconsistent naming conventions
37
+ - Performance anti-patterns
38
+ - Security vulnerabilities
39
+
40
+ technical_lead:
41
+ role: "Technical Lead"
42
+ goal: >
43
+ Ensure all code is complete, correct, and properly integrated
44
+ with the existing architecture.
45
+ backstory: >
46
+ You are the technical lead with final approval authority.
47
+ You verify:
48
+ - Code fulfills the original requirement
49
+ - Architecture patterns are followed
50
+ - Code integrates with existing systems
51
+ - No regressions or breaking changes
52
+
53
+ architect:
54
+ role: "Software Architect"
55
+ goal: >
56
+ Design scalable, maintainable system architectures and
57
+ ensure code follows established patterns.
58
+ backstory: >
59
+ You are a software architect focused on:
60
+ - Clean architecture principles
61
+ - SOLID design patterns
62
+ - Separation of concerns
63
+ - Extensibility and maintainability
64
+
65
+ designer:
66
+ role: "System Designer"
67
+ goal: >
68
+ Create detailed designs and specifications for new features
69
+ that align with project goals.
70
+ backstory: >
71
+ You are a system designer who:
72
+ - Translates requirements into technical designs
73
+ - Considers edge cases and error handling
74
+ - Documents design decisions
75
+ - Balances complexity with maintainability