decepticon-core 1.1.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.
Files changed (36) hide show
  1. decepticon_core-1.1.2/.gitignore +117 -0
  2. decepticon_core-1.1.2/PKG-INFO +43 -0
  3. decepticon_core-1.1.2/README.md +20 -0
  4. decepticon_core-1.1.2/decepticon_core/__init__.py +43 -0
  5. decepticon_core-1.1.2/decepticon_core/contracts/__init__.py +35 -0
  6. decepticon_core-1.1.2/decepticon_core/contracts/contributions.py +153 -0
  7. decepticon_core-1.1.2/decepticon_core/contracts/slots.py +135 -0
  8. decepticon_core-1.1.2/decepticon_core/plugin_loader.py +671 -0
  9. decepticon_core-1.1.2/decepticon_core/protocols/__init__.py +41 -0
  10. decepticon_core-1.1.2/decepticon_core/protocols/agent.py +31 -0
  11. decepticon_core-1.1.2/decepticon_core/protocols/backend.py +38 -0
  12. decepticon_core-1.1.2/decepticon_core/protocols/callback.py +31 -0
  13. decepticon_core-1.1.2/decepticon_core/protocols/llm.py +28 -0
  14. decepticon_core-1.1.2/decepticon_core/protocols/middleware.py +43 -0
  15. decepticon_core-1.1.2/decepticon_core/protocols/sandbox.py +32 -0
  16. decepticon_core-1.1.2/decepticon_core/protocols/tool.py +32 -0
  17. decepticon_core-1.1.2/decepticon_core/py.typed +0 -0
  18. decepticon_core-1.1.2/decepticon_core/registry/__init__.py +55 -0
  19. decepticon_core-1.1.2/decepticon_core/registry/conflict.py +42 -0
  20. decepticon_core-1.1.2/decepticon_core/registry/plugins.py +238 -0
  21. decepticon_core-1.1.2/decepticon_core/registry/resolution.py +69 -0
  22. decepticon_core-1.1.2/decepticon_core/registry/roles.py +94 -0
  23. decepticon_core-1.1.2/decepticon_core/registry/safety.py +87 -0
  24. decepticon_core-1.1.2/decepticon_core/registry/skills.py +67 -0
  25. decepticon_core-1.1.2/decepticon_core/types/__init__.py +23 -0
  26. decepticon_core-1.1.2/decepticon_core/types/engagement.py +1073 -0
  27. decepticon_core-1.1.2/decepticon_core/types/kg.py +374 -0
  28. decepticon_core-1.1.2/decepticon_core/types/llm.py +776 -0
  29. decepticon_core-1.1.2/decepticon_core/utils/__init__.py +12 -0
  30. decepticon_core-1.1.2/decepticon_core/utils/config.py +69 -0
  31. decepticon_core-1.1.2/decepticon_core/utils/logging.py +120 -0
  32. decepticon_core-1.1.2/pyproject.toml +51 -0
  33. decepticon_core-1.1.2/tests/test_no_runtime_deps.py +74 -0
  34. decepticon_core-1.1.2/tests/test_plugin_registry.py +153 -0
  35. decepticon_core-1.1.2/tests/test_public_api_stability.py +137 -0
  36. decepticon_core-1.1.2/tests/test_safety_registry.py +106 -0
@@ -0,0 +1,117 @@
1
+ # Environments
2
+ .env
3
+ .venv
4
+ env/
5
+ venv/
6
+ ENV/
7
+ env.bak/
8
+ venv.bak/
9
+
10
+ # Byte-compiled / optimized / DLL files
11
+ __pycache__/
12
+ *.py[cod]
13
+ *$py.class
14
+
15
+ # IDE and Editor
16
+ .vscode/
17
+ .idea/
18
+ *.swp
19
+ *.swo
20
+
21
+ # Python specific
22
+ build/
23
+ develop-eggs/
24
+ dist/
25
+ downloads/
26
+ eggs/
27
+ .eggs/
28
+ parts/
29
+ sdist/
30
+ var/
31
+ wheels/
32
+ share/python-wheels/
33
+ *.egg-info/
34
+ .installed.cfg
35
+ *.egg
36
+
37
+ # Coverage reports
38
+ htmlcov/
39
+ .tox/
40
+ .nox/
41
+ .coverage
42
+ .coverage.*
43
+ .cache
44
+ nosetests.xml
45
+ coverage.xml
46
+ *.cover
47
+ *.py,cover
48
+ .hypothesis/
49
+ .pytest_cache/
50
+
51
+ # Jupyter Notebook
52
+ .ipynb_checkpoints
53
+
54
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
55
+ __pypackages__/
56
+
57
+ # OS generated files
58
+ .DS_Store
59
+ .DS_Store?
60
+ ._*
61
+ .Spotlight-V100
62
+ .Trashes
63
+ ehthumbs.db
64
+ Thumbs.db
65
+
66
+ # Node
67
+ node_modules/
68
+
69
+ # etc
70
+ sliver-py/
71
+ /src/
72
+ config/*.local.*
73
+ reference/
74
+ demo.tape
75
+
76
+ # Decepticon runtime data
77
+ .decepticon/
78
+ .dogfood/
79
+ workspace/
80
+ .bg-shell/
81
+
82
+ .langgraph_api/
83
+ .omc/
84
+ .ouroboros/
85
+ .gstack/
86
+ .claude/
87
+ clients/ee/
88
+
89
+ # Project-specific Claude Code instructions (private)
90
+ CLAUDE.md
91
+ references/octogent
92
+ clients/launcher/decepticon
93
+
94
+ # Benchmark
95
+ # Per-run artefacts (timestamped batch + evidence/ + reports/) are local-only.
96
+ # Curated per-challenge results (XBEN-*-24/) and the LEVEL3 index are committed.
97
+ # LangSmith trace dumps live as public share URLs in READMEs — never committed.
98
+ benchmark/results/*
99
+ !benchmark/results/.gitkeep
100
+ !benchmark/results/XBEN-*-24/
101
+ !benchmark/results/README.md
102
+ benchmark/results/XBEN-*-24/evidence/langsmith_trace.json
103
+ benchmark/results/XBEN-*-24/evidence/iter14_pass.json
104
+ benchmark/results/XBEN-*-24/evidence/*_iter*.json
105
+ # Per-run timestamped subdirs inside XBEN-*-24/ are local dev artefacts.
106
+ # The flat root (report.json / report.md / evidence/summary.{json,md}) is the
107
+ # committed PASS record — see benchmark/results/README.md for the policy.
108
+ benchmark/results/XBEN-*-24/2[0-9][0-9][0-9][0-9][0-9][0-9][0-9]_*/
109
+ benchmark/workspaces/
110
+
111
+ # Codex / OMX runtime artefacts (never committed)
112
+ .omx/
113
+ .env.bak.*
114
+ benchmark/results/XBEN-*-24/run-loop*.log
115
+
116
+ # Git worktrees
117
+ .worktrees/
@@ -0,0 +1,43 @@
1
+ Metadata-Version: 2.4
2
+ Name: decepticon-core
3
+ Version: 1.1.2
4
+ Summary: Decepticon contract layer: pure types, protocols, plugin contracts, registry primitives
5
+ Project-URL: Homepage, https://github.com/PurpleAILAB/Decepticon
6
+ Project-URL: Repository, https://github.com/PurpleAILAB/Decepticon
7
+ Author: Decepticon Team
8
+ License: Apache-2.0
9
+ Keywords: agents,ai,contracts,plugins,red-team,security
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: Apache Software License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Security
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: >=3.13
19
+ Requires-Dist: pydantic-settings>=2.0.0
20
+ Requires-Dist: pydantic>=2.0.0
21
+ Requires-Dist: typing-extensions>=4.0.0
22
+ Description-Content-Type: text/markdown
23
+
24
+ # decepticon-core
25
+
26
+ The Decepticon contract layer. Pure types, protocols, plugin contracts,
27
+ and registry primitives — zero `langchain` / `langgraph` / `deepagents`
28
+ runtime dependency. Suitable to import from any context: CLI tooling,
29
+ serverless workers, type-checking-only environments.
30
+
31
+ Stable surface for plugin authors and downstream commercial layers
32
+ (e.g. SaaS dashboards, B2B API services). See the umbrella
33
+ [`README.md`](../../README.md) and the design spec at
34
+ [`docs/superpowers/specs/2026-05-23-core-framework-sdk-split-design.md`](../../docs/superpowers/specs/2026-05-23-core-framework-sdk-split-design.md).
35
+
36
+ ## Install
37
+
38
+ ```bash
39
+ pip install decepticon-core
40
+ ```
41
+
42
+ Most consumers should install `decepticon` (which depends on this) or
43
+ `decepticon-sdk` (the plugin-author entrypoint).
@@ -0,0 +1,20 @@
1
+ # decepticon-core
2
+
3
+ The Decepticon contract layer. Pure types, protocols, plugin contracts,
4
+ and registry primitives — zero `langchain` / `langgraph` / `deepagents`
5
+ runtime dependency. Suitable to import from any context: CLI tooling,
6
+ serverless workers, type-checking-only environments.
7
+
8
+ Stable surface for plugin authors and downstream commercial layers
9
+ (e.g. SaaS dashboards, B2B API services). See the umbrella
10
+ [`README.md`](../../README.md) and the design spec at
11
+ [`docs/superpowers/specs/2026-05-23-core-framework-sdk-split-design.md`](../../docs/superpowers/specs/2026-05-23-core-framework-sdk-split-design.md).
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pip install decepticon-core
17
+ ```
18
+
19
+ Most consumers should install `decepticon` (which depends on this) or
20
+ `decepticon-sdk` (the plugin-author entrypoint).
@@ -0,0 +1,43 @@
1
+ """decepticon-core — contract layer for the Decepticon agent framework.
2
+
3
+ Pure types, protocols, plugin contracts, and registry primitives. This
4
+ package never imports ``langchain``, ``langgraph``, ``deepagents``,
5
+ ``httpx``, or ``fastapi`` — see the design spec at
6
+ ``docs/superpowers/specs/2026-05-23-core-framework-sdk-split-design.md``.
7
+
8
+ Phase 1.A status: ``types`` submodule extracted from the framework
9
+ (engagement / llm / kg). Subsequent commits add ``protocols``,
10
+ ``contracts``, ``registry``, and ``utils`` per spec §6.1.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from importlib.metadata import PackageNotFoundError
16
+ from importlib.metadata import version as _version
17
+
18
+ from decepticon_core import (
19
+ contracts,
20
+ plugin_loader,
21
+ protocols,
22
+ registry,
23
+ types,
24
+ utils,
25
+ )
26
+
27
+ try:
28
+ # pyproject carries a "0.0.0" sentinel; release.yml stamps the real
29
+ # tag into the wheel metadata at build time, and importlib.metadata
30
+ # reads it back here. Local checkouts read 0.0.0.
31
+ __version__ = _version("decepticon-core")
32
+ except PackageNotFoundError:
33
+ __version__ = "0.0.0"
34
+
35
+ __all__ = [
36
+ "__version__",
37
+ "contracts",
38
+ "plugin_loader",
39
+ "protocols",
40
+ "registry",
41
+ "types",
42
+ "utils",
43
+ ]
@@ -0,0 +1,35 @@
1
+ """Plugin contracts — the surface plugin authors implement against.
2
+
3
+ Submodules:
4
+
5
+ * ``slots`` — middleware slot enum and per-role applicability mapping.
6
+ Was ``decepticon.agents.middleware_slots``; framework keeps the
7
+ default factory helpers (which need langchain runtime) and imports
8
+ the enum/constants from here.
9
+
10
+ Future Phase 1 commits will add ``contributions`` (ToolContribution,
11
+ MiddlewareContribution, PromptContribution, SubAgentContribution,
12
+ SafetyDeclaration) and ``PluginBundle`` proper (currently lives at
13
+ ``decepticon_core.plugin_loader`` after Phase 1.B).
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from decepticon_core.contracts import contributions, slots
19
+ from decepticon_core.contracts.contributions import (
20
+ MiddlewareContribution,
21
+ PromptContribution,
22
+ SafetyDeclaration,
23
+ SubAgentContribution,
24
+ ToolContribution,
25
+ )
26
+
27
+ __all__ = [
28
+ "MiddlewareContribution",
29
+ "PromptContribution",
30
+ "SafetyDeclaration",
31
+ "SubAgentContribution",
32
+ "ToolContribution",
33
+ "contributions",
34
+ "slots",
35
+ ]
@@ -0,0 +1,153 @@
1
+ """Focused contribution dataclasses for plugin authors.
2
+
3
+ Per spec §7.2 Principle 3, the kitchen-sink ``PluginBundle`` of the
4
+ pre-redesign era splits into five focused contribution types — each
5
+ covers one extension surface so plugin authors construct just what
6
+ they need and the framework's introspection (``PluginRegistry``)
7
+ attributes overrides to specific contributions.
8
+
9
+ The aggregate ``PluginBundle`` (currently at
10
+ ``decepticon_core.plugin_loader``) keeps a back-compat shape during
11
+ the transition; Phase 2 introduces the rebuilt version that aggregates
12
+ these contributions.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from collections.abc import Mapping
18
+ from dataclasses import dataclass, field
19
+ from typing import Any, Literal
20
+
21
+
22
+ @dataclass(frozen=True)
23
+ class ToolContribution:
24
+ """Tools a plugin contributes to one or more roles.
25
+
26
+ Mirrors the old ``PluginBundle.replaced_tools`` / ``disabled_tools``
27
+ fields, but typed precisely and with the ``roles`` field
28
+ intentionally required (no implicit "all roles" — closes gap §8
29
+ #6). An empty ``roles`` tuple raises ``ValueError`` at construction.
30
+
31
+ Fields:
32
+ items: tools added to the role's tool list.
33
+ disabled_names: tool names to remove from the OSS baseline.
34
+ replaced: name -> replacement tool (combines disable + add).
35
+ roles: roles this contribution applies to. ``()`` is rejected
36
+ at construction time.
37
+ """
38
+
39
+ items: tuple[Any, ...] = ()
40
+ disabled_names: tuple[str, ...] = ()
41
+ replaced: Mapping[str, Any] = field(default_factory=dict)
42
+ roles: tuple[str, ...] = ()
43
+
44
+ def __post_init__(self) -> None:
45
+ if not self.roles:
46
+ raise ValueError(
47
+ "ToolContribution requires an explicit non-empty ``roles=`` tuple "
48
+ "(closes spec §8 gap #6 — implicit all-roles is forbidden). "
49
+ "Pass roles=('recon',) etc."
50
+ )
51
+
52
+
53
+ @dataclass(frozen=True)
54
+ class MiddlewareContribution:
55
+ """Middleware a plugin contributes to one or more roles.
56
+
57
+ Same shape as ``ToolContribution`` but keyed by slot name (the
58
+ ``MiddlewareSlot`` value). ``roles`` is required at construction.
59
+ """
60
+
61
+ items: tuple[Any, ...] = ()
62
+ disabled_slots: tuple[str, ...] = ()
63
+ replaced_slots: Mapping[str, Any] = field(default_factory=dict)
64
+ roles: tuple[str, ...] = ()
65
+
66
+ def __post_init__(self) -> None:
67
+ if not self.roles:
68
+ raise ValueError(
69
+ "MiddlewareContribution requires an explicit non-empty "
70
+ "``roles=`` tuple (closes spec §8 gap #6). Pass roles=('recon',) etc."
71
+ )
72
+
73
+
74
+ @dataclass(frozen=True)
75
+ class PromptContribution:
76
+ """Prompt fragments a plugin contributes to one or more roles.
77
+
78
+ Closes gap §8 #8 (prompt-only plugin no longer has to wrap in
79
+ ``PluginBundle``) — packages can ship a ``PromptContribution``
80
+ directly under the new ``decepticon.prompts`` entry-point group.
81
+
82
+ Fields:
83
+ fragments: role name -> text. The framework applies the
84
+ fragment per the ``mode`` setting.
85
+ mode: ``prepend`` / ``append`` / ``replace`` (replace wholly
86
+ substitutes the loaded prompt; prepend/append wrap it).
87
+ roles: roles this contribution applies to.
88
+ """
89
+
90
+ fragments: Mapping[str, str] = field(default_factory=dict)
91
+ mode: Literal["prepend", "append", "replace"] = "append"
92
+ roles: tuple[str, ...] = ()
93
+
94
+ def __post_init__(self) -> None:
95
+ if not self.roles:
96
+ raise ValueError(
97
+ "PromptContribution requires an explicit non-empty ``roles=`` "
98
+ "tuple (closes spec §8 gap #6). Pass roles=('recon',) etc."
99
+ )
100
+
101
+
102
+ @dataclass(frozen=True)
103
+ class SubAgentContribution:
104
+ """Sub-agents a plugin contributes to one or more parent agents.
105
+
106
+ Mirrors the parent-agent scoping used by ``load_subagents_for_parent``
107
+ in ``decepticon_core.plugin_loader``. The ``items`` carry
108
+ ``SubAgentSpec`` objects (defined in plugin_loader, eventually to
109
+ move under ``contracts``). ``parent_agents`` required.
110
+ """
111
+
112
+ items: tuple[Any, ...] = ()
113
+ disabled_names: tuple[str, ...] = ()
114
+ replaced: Mapping[str, Any] = field(default_factory=dict)
115
+ parent_agents: tuple[str, ...] = ()
116
+
117
+ def __post_init__(self) -> None:
118
+ if not self.parent_agents:
119
+ raise ValueError(
120
+ "SubAgentContribution requires an explicit non-empty "
121
+ "``parent_agents=`` tuple (closes spec §8 gap #6). "
122
+ "Pass parent_agents=('decepticon',) etc."
123
+ )
124
+
125
+
126
+ @dataclass(frozen=True)
127
+ class SafetyDeclaration:
128
+ """Plugin-declared additions to the safety-critical set.
129
+
130
+ Per spec §16.4 #4 this contract is **additive only**: plugins can
131
+ declare *their own* tool / middleware names safety-critical, but
132
+ cannot remove safety on OSS-declared names. The framework merges
133
+ plugin SafetyDeclarations with ``SAFETY_CRITICAL_TOOLS`` /
134
+ ``SAFETY_CRITICAL_SLOTS`` from ``decepticon-core``.
135
+
136
+ Fields:
137
+ tools: tool names the plugin marks safety-critical.
138
+ middleware: middleware slot names the plugin marks
139
+ safety-critical. Custom plugin slot names are accepted
140
+ (any string).
141
+ """
142
+
143
+ tools: tuple[str, ...] = ()
144
+ middleware: tuple[str, ...] = ()
145
+
146
+
147
+ __all__ = [
148
+ "MiddlewareContribution",
149
+ "PromptContribution",
150
+ "SafetyDeclaration",
151
+ "SubAgentContribution",
152
+ "ToolContribution",
153
+ ]
@@ -0,0 +1,135 @@
1
+ """Middleware slot enum and per-role applicability mapping.
2
+
3
+ The Decepticon agent factories assemble their middleware stack by
4
+ walking ``MiddlewareSlot`` in declaration order; each role declares
5
+ which slots apply via ``SLOTS_PER_ROLE``.
6
+
7
+ This module is the pure-data half of the original
8
+ ``decepticon.agents.middleware_slots``. The langchain/deepagents-bound
9
+ default factories (``DEFAULT_SLOT_FACTORIES`` and the ``_make_*``
10
+ helpers) stay in the framework — keeping core langchain-free.
11
+
12
+ Plugin authors implementing custom middleware reach for
13
+ ``MiddlewareSlot`` and the ``SAFETY_CRITICAL_SLOTS`` set when wiring
14
+ ``PluginBundle.replaced_middleware`` / ``disabled_middleware``.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ from enum import StrEnum
20
+
21
+
22
+ class MiddlewareSlot(StrEnum):
23
+ """Named slots in the agent middleware stack.
24
+
25
+ Enum declaration order = assembly order. The 16 agent factories
26
+ walk this enum top-to-bottom; only slots in ``SLOTS_PER_ROLE[role]``
27
+ are instantiated.
28
+ """
29
+
30
+ ENGAGEMENT_CONTEXT = "engagement-context"
31
+ SKILLS = "skills"
32
+ FILESYSTEM = "filesystem"
33
+ SUBAGENT = "subagent"
34
+ OPPLAN = "opplan"
35
+ SANDBOX_NOTIFICATION = "sandbox-notification"
36
+ MODEL_OVERRIDE = "model-override"
37
+ MODEL_FALLBACK = "model-fallback"
38
+ SUMMARIZATION = "summarization"
39
+ PROMPT_CACHING = "prompt-caching"
40
+ PATCH_TOOL_CALLS = "patch-tool-calls"
41
+
42
+
43
+ SAFETY_CRITICAL_SLOTS: frozenset[MiddlewareSlot] = frozenset(
44
+ {
45
+ # EngagementContextMiddleware carries RoE constraints into every
46
+ # tool call — disabling it lets an agent target out-of-scope
47
+ # hosts without any guard rail. Replacement is fine if the new
48
+ # middleware honours the same contract; full disable is the
49
+ # actual hazard.
50
+ MiddlewareSlot.ENGAGEMENT_CONTEXT,
51
+ # SandboxNotification tracks background-job completion + emits
52
+ # the CLI's ``● Background command`` event. Disabling it leaves
53
+ # operator visibility broken on every background tool call.
54
+ MiddlewareSlot.SANDBOX_NOTIFICATION,
55
+ }
56
+ )
57
+ """Slots a plugin can only replace/disable when
58
+ ``DECEPTICON_ALLOW_SAFETY_OVERRIDES=1`` is set in the environment.
59
+
60
+ The gate is enforced by ``build_middleware`` in
61
+ ``decepticon.agents.build``. Plugins are expected to honour the
62
+ overall contract (e.g. a replacement EngagementContextMiddleware still
63
+ needs to inject scope) — the gate exists so an accidentally-installed
64
+ plugin can't silently subvert the safety story.
65
+ """
66
+
67
+
68
+ # Common slots every agent uses (the "tail" of the middleware stack).
69
+ _TAIL_SLOTS: frozenset[MiddlewareSlot] = frozenset(
70
+ {
71
+ MiddlewareSlot.MODEL_FALLBACK,
72
+ MiddlewareSlot.SUMMARIZATION,
73
+ MiddlewareSlot.PROMPT_CACHING,
74
+ MiddlewareSlot.PATCH_TOOL_CALLS,
75
+ }
76
+ )
77
+
78
+ # Base slots — knowledge + filesystem + tail. Every agent gets these.
79
+ _BASE_SLOTS: frozenset[MiddlewareSlot] = _TAIL_SLOTS | {
80
+ MiddlewareSlot.SKILLS,
81
+ MiddlewareSlot.FILESYSTEM,
82
+ }
83
+
84
+ # Standard bash-executing agents (recon/exploit/postexploit/analyst/
85
+ # reverser/contract_auditor/cloud_hunter/ad_operator + plugin
86
+ # specialists verifier/patcher/scanner/exploiter): base + engagement
87
+ # context + sandbox notification.
88
+ _BASH_AGENT_SLOTS: frozenset[MiddlewareSlot] = _BASE_SLOTS | {
89
+ MiddlewareSlot.ENGAGEMENT_CONTEXT,
90
+ MiddlewareSlot.SANDBOX_NOTIFICATION,
91
+ }
92
+
93
+
94
+ SLOTS_PER_ROLE: dict[str, frozenset[MiddlewareSlot]] = {
95
+ # ── Standard orchestrator ──
96
+ "decepticon": _BASE_SLOTS
97
+ | {
98
+ MiddlewareSlot.ENGAGEMENT_CONTEXT,
99
+ MiddlewareSlot.SUBAGENT,
100
+ MiddlewareSlot.OPPLAN,
101
+ MiddlewareSlot.MODEL_OVERRIDE,
102
+ },
103
+ # ── Standard non-bash agent (planning + interview) ──
104
+ "soundwave": _BASE_SLOTS | {MiddlewareSlot.ENGAGEMENT_CONTEXT},
105
+ # ── Standard bash-executing specialists ──
106
+ "recon": _BASH_AGENT_SLOTS,
107
+ "exploit": _BASH_AGENT_SLOTS,
108
+ "postexploit": _BASH_AGENT_SLOTS,
109
+ "analyst": _BASH_AGENT_SLOTS,
110
+ "reverser": _BASH_AGENT_SLOTS,
111
+ "contract_auditor": _BASH_AGENT_SLOTS,
112
+ "cloud_hunter": _BASH_AGENT_SLOTS,
113
+ "ad_operator": _BASH_AGENT_SLOTS,
114
+ # ── Plugin orchestrator (no EngagementContext per the existing
115
+ # vulnresearch factory — it consumes its parent's context) ──
116
+ "vulnresearch": _BASE_SLOTS | {MiddlewareSlot.SUBAGENT, MiddlewareSlot.OPPLAN},
117
+ # ── Plugin read-only specialist (no bash, no SandboxNotification) ──
118
+ "detector": _BASE_SLOTS,
119
+ # ── Plugin bash-executing specialists ──
120
+ "verifier": _BASH_AGENT_SLOTS,
121
+ "patcher": _BASH_AGENT_SLOTS,
122
+ "scanner": _BASH_AGENT_SLOTS,
123
+ "exploiter": _BASH_AGENT_SLOTS,
124
+ }
125
+ """Role → slot-set mapping. The assembler only walks slots present in
126
+ the role's set; anything else is skipped silently. Plugin agents
127
+ register their own role here via the ``decepticon.agents`` entry-point
128
+ group (handled by ``plugin_loader``)."""
129
+
130
+
131
+ __all__ = [
132
+ "MiddlewareSlot",
133
+ "SAFETY_CRITICAL_SLOTS",
134
+ "SLOTS_PER_ROLE",
135
+ ]