Skip to content

exploration: DirectivePolicy — per-agent directive suppression (do not implement without demand) #1101

@chubes4

Description

@chubes4

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)

  1. 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.
  2. 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.
  3. 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).
  4. 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.
  5. 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:

  1. 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).
  2. A third-party plugin registers directives that need to be agent-gated without plugin-level coordination.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions