Skip to content

feat(config): inject configurable files into the system prompt#157

Merged
PleasePrompto merged 1 commit into
PleasePrompto:mainfrom
ryuhaneul:feat/append-system-prompt-files
Jul 12, 2026
Merged

feat(config): inject configurable files into the system prompt#157
PleasePrompto merged 1 commit into
PleasePrompto:mainfrom
ryuhaneul:feat/append-system-prompt-files

Conversation

@ryuhaneul

Copy link
Copy Markdown
Contributor

Motivation

Ductor already auto-appends MAINMEMORY.md to the system prompt (on new sessions), but there's no way to inject additional files — extra context or reference documents — that you want present on every turn. This adds a small config option to do exactly that.

What it adds

  • New config key append_system_prompt_files: list[str] (default []): a list of workspace-relative filenames whose contents are appended to the agent's --append-system-prompt for agent-driven turns.
    • List multiple files to inject several — they're concatenated in the listed order, e.g. "append_system_prompt_files": ["GLOSSARY.md", "STYLE_GUIDE.md"].
  • Each agent reads the files from its own workspace, so the main agent and each sub-agent can carry different content under the same filenames. Sub-agents inherit the list from the main config.
  • Injected on every turn (not just new sessions), so it survives compaction — like the existing MAINMEMORY.md mechanism, but always-on.

Where it injects (and where it doesn't)

Wired into the agent-driven request paths: normal chat, named sessions (sync + streaming), inter-agent messages (incl. retry), tasks, and background named sessions. Intentionally excluded from system-maintenance turns — heartbeat, memory flush, and compaction.

Safety

  • Default [] → no change to current behavior.
  • Missing files are silently skipped (no error).
  • Filenames are confined to the workspace: absolute paths, .., and symlink escapes are ignored (resolved and checked against the workspace root).

Tests

Coverage for the helper (concat / empty / missing / path-escape guards), every-turn injection (including resume), per-agent workspace resolution, and the maintenance-flow exclusions.

…pend_system_prompt_files

Add an opt-in append_system_prompt_files list to AgentConfig: each
workspace-relative filename's contents are appended to the system prompt
of agent-driven turns. Default empty list preserves current behavior, and
missing/empty files are skipped silently.

A shared async helper build_appended_files_block reads the files from the
agent's own workspace, with a resolve()+is_relative_to path-escape guard
(absolute paths, .., and workspace symlinks escaping the workspace are
skipped). It returns None when nothing applies so callers leave
append_system_prompt unchanged.

Wired into the 8 agent-driven AgentRequest points: normal turns
(_prepare_normal, every turn after mainmemory/roster), named-session flow +
streaming, inter-agent injection (_inject_prompt, interagent message,
retry), the task hub, and background named sessions. The task hub resolves
each task's parent-agent workspace; the background observer gains a config
param. MAINMEMORY injection is unchanged.

The maintenance flows are intentionally excluded (no injection): heartbeat,
memory flush, and memory compaction.
@PleasePrompto
PleasePrompto merged commit 4064313 into PleasePrompto:main Jul 12, 2026
PleasePrompto added a commit that referenced this pull request Jul 12, 2026
Follow-up to #157: skip files over 256 KiB (the block is re-injected on
every turn), add the key to docs/config.md and config.example.json.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PleasePrompto added a commit that referenced this pull request Jul 12, 2026
- cron one-shot Claude command: gate --effort on the 'default' sentinel
  like the -p path, instead of silently dropping an explicit 'medium'
- extract TaskHub._prepare_request from _run (PLR0915 after the #157/#164
  merges pushed _run past 50 statements)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PleasePrompto added a commit that referenced this pull request Jul 12, 2026
Post-merge fixes threading the Slack transport through main's newer
subsystems (#164 per-session effort, #157 append_system_prompt_files,
#166 topic-scoped kills, #137/#138 task changes):

- Delete fork-only .github/workflows/upstream-release-watch.yml
- Remove dead _is_message_addressed() in messenger/slack/bot.py
- Fix trailing comma in config.example.json Slack section (invalid JSON)
- Drop fork-only "ductor-slack" brand strings from en/wizard.toml
- Harden _normalized_transport_list() in __main__.py: honor a non-empty
  transports list whenever the primary is a member (primary-first, others
  preserved) instead of collapsing to [primary] on any ordering mismatch,
  so telegram+matrix multi-transport setups are never silently dropped;
  add regression tests
- named.py create(): keep both reasoning_effort and key params (# noqa:
  PLR0913, matching the codebase convention e.g. tasks/registry.py)
- Update #164 create() test stubs for the new key kwarg
- mypy: guard the optional slack_bolt import behind TYPE_CHECKING/else to
  satisfy strict no-redef
- uv lock: add slack-bolt/slack-sdk (also picks up pre-existing lock drift)
- ruff format integration-touched files

Note: orch._sessions.list_active_for_chat() in slack/bot.py follows the
existing private-access convention (telegram/startup.py does the same);
no public accessor exists.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants