Status
Exploration / speculative. No concrete user need filed. Opening to capture design shape now that MemoryPolicy (#1099, PR #1100) has shipped and the parallel structure with ToolPolicy (0.39.0) is starting to look like a pattern worth naming.
Do not implement from this issue without validating demand. See "Red flags" below.
The observation
Two per-agent declarative policies now exist:
Both follow the same shape: per-agent config key, deny/allow semantics, context presets (pipeline/chat/system), consumed by the layer it scopes (tool manager vs directive stack).
The directive stack itself is the next plausible candidate for the pattern. Directives are currently registered globally via the datamachine_directives filter and fire for all agents uniformly; their contexts array gates which requests they apply to, but there is no per-agent suppression.
Current directive system (for reference)
Directives are priority-ordered plugins into the prompt-building pipeline. Each one returns zero or more system_text blocks that inject into the AI request.
| Priority |
Directive |
Purpose |
| 20 |
CoreMemoryFilesDirective |
Registered memory files via MemoryPolicyResolver (post #1100) |
| 40 |
PipelineMemoryFilesDirective |
pipeline_config.memory_files |
| 45 |
FlowMemoryFilesDirective |
flow_config.memory_files |
| 46 |
DailyMemorySelectorDirective |
Daily journal entries |
| 50 |
PipelineSystemPromptDirective |
Pipeline instructions |
| 60 |
ClientContextDirective |
Client-provided context payload |
| 80 |
SiteContextDirective (deprecated — now in SITE.md) |
Legacy site metadata |
| — |
ChatPipelinesDirective |
Chat-specific pipeline context |
Registration happens per-directive via add_filter('datamachine_directives', ...). Assembly happens in RequestBuilder::build_request() → PromptBuilder::build().
Hypothetical DirectivePolicy shape
If the pattern were to apply:
{
"directive_policy": {
"mode": "deny",
"deny": ["ClientContextDirective", "DailyMemorySelectorDirective"]
}
}
Or:
{
"directive_policy": {
"mode": "allow_only",
"allow_only": ["CoreMemoryFilesDirective", "PipelineSystemPromptDirective"]
}
}
Mirrored resolver would sit between RequestBuilder's apply_filters('datamachine_directives', ...) and PromptBuilder::addDirective(), filtering the directive list by the agent's policy.
Possible use cases (speculative)
- Stateless AI steps in pipelines — an AI step that is purely transformational (e.g. summarize this packet) doesn't need memory directives, client context, or pipeline system prompt overhead. Could run with
allow_only: [...] to keep only what's strictly needed.
- Debugging — temporarily suppress specific directives to isolate prompt issues.
- Cost/latency optimization — trim directives for high-volume cheap agents.
- Third-party directive gating — agents can opt out of directives registered by other plugins without editing those plugins.
Red flags (why this may not be worth building)
- No filed demand. Unlike ToolPolicy and MemoryPolicy, which had concrete use cases (agent-specific tool access; stateless wiki agents), nothing in the issue tracker or recent sessions asks for directive-level suppression.
- Contexts already provide coarse gating. Each directive declares which contexts it applies to. Many "I don't want this directive" cases might be solvable by fixing the directive's
contexts array instead of adding a per-agent override.
- MemoryPolicy covers the common case. The directives most likely to be suppressed are memory-related, and MemoryPolicy already handles those at a finer grain (which files, not which directive wholesale).
- Directive class names as the policy vocabulary is awkward.
allow_only: ["CoreMemoryFilesDirective"] exposes implementation detail. Would probably want a friendlier ID system (slugs, labels) before shipping, which is additional design work.
- Abstraction-on-N=2 risk. Building DirectivePolicy to "complete the pattern" is the textbook trap — shape the abstraction to fit what exists, then discover the next real policy doesn't fit at all.
Proposed criteria for unblocking
Ship this only if one of the following is true:
- A user files a concrete issue that can ONLY be solved by per-agent directive suppression (not by fixing directive contexts or using existing MemoryPolicy).
- A third-party plugin registers directives that need to be agent-gated without plugin-level coordination.
- A clear cost/latency case emerges from telemetry — specific agents running high-volume with provable directive overhead worth cutting.
Otherwise, leave this as a design note and point future policy work back here when a third policy ever lands organically.
Related
Out of scope for this issue
- Actually building it
- Designing the directive ID/slug vocabulary
- Deciding whether a shared
AbstractAgentPolicy base class should land first
Those belong to a separate feature issue IF demand materializes.
Status
Exploration / speculative. No concrete user need filed. Opening to capture design shape now that MemoryPolicy (#1099, PR #1100) has shipped and the parallel structure with ToolPolicy (0.39.0) is starting to look like a pattern worth naming.
Do not implement from this issue without validating demand. See "Red flags" below.
The observation
Two per-agent declarative policies now exist:
agent_config.tool_policy— filters tools viaToolPolicyResolver(0.39.0)agent_config.memory_policy— filters memory files viaMemoryPolicyResolver(PR feat(memory): MemoryPolicy — per-agent memory file policy (closes #1099) #1100)Both follow the same shape: per-agent config key, deny/allow semantics, context presets (
pipeline/chat/system), consumed by the layer it scopes (tool manager vs directive stack).The directive stack itself is the next plausible candidate for the pattern. Directives are currently registered globally via the
datamachine_directivesfilter and fire for all agents uniformly; their contexts array gates which requests they apply to, but there is no per-agent suppression.Current directive system (for reference)
Directives are priority-ordered plugins into the prompt-building pipeline. Each one returns zero or more
system_textblocks that inject into the AI request.CoreMemoryFilesDirectiveMemoryPolicyResolver(post #1100)PipelineMemoryFilesDirectivepipeline_config.memory_filesFlowMemoryFilesDirectiveflow_config.memory_filesDailyMemorySelectorDirectivePipelineSystemPromptDirectiveClientContextDirectiveSiteContextDirective(deprecated — now in SITE.md)ChatPipelinesDirectiveRegistration happens per-directive via
add_filter('datamachine_directives', ...). Assembly happens inRequestBuilder::build_request()→PromptBuilder::build().Hypothetical DirectivePolicy shape
If the pattern were to apply:
{ "directive_policy": { "mode": "deny", "deny": ["ClientContextDirective", "DailyMemorySelectorDirective"] } }Or:
{ "directive_policy": { "mode": "allow_only", "allow_only": ["CoreMemoryFilesDirective", "PipelineSystemPromptDirective"] } }Mirrored resolver would sit between
RequestBuilder'sapply_filters('datamachine_directives', ...)andPromptBuilder::addDirective(), filtering the directive list by the agent's policy.Possible use cases (speculative)
allow_only: [...]to keep only what's strictly needed.Red flags (why this may not be worth building)
contextsarray instead of adding a per-agent override.allow_only: ["CoreMemoryFilesDirective"]exposes implementation detail. Would probably want a friendlier ID system (slugs, labels) before shipping, which is additional design work.Proposed criteria for unblocking
Ship this only if one of the following is true:
Otherwise, leave this as a design note and point future policy work back here when a third policy ever lands organically.
Related
inc/Engine/AI/Tools/ToolPolicyResolver.php— reference implementation (0.39.0)inc/Engine/AI/Memory/MemoryPolicyResolver.php— reference implementation (post feat(memory): MemoryPolicy — per-agent memory file policy (closes #1099) #1100)inc/Engine/AI/PromptBuilder.php— directive assemblyinc/Engine/AI/RequestBuilder.php— directive filter consumptionOut of scope for this issue
AbstractAgentPolicybase class should land firstThose belong to a separate feature issue IF demand materializes.