# Feature Flags (file presence vs config) **Status:** Styleguide; codifies when to use file-presence flags ("delete to turn off") vs config flags (`[ai_settings.toml]` / `[manual_slop.toml]`). **Date:** 2026-06-12 **Cross-refs:** `conductor/code_styleguides/knowledge_artifacts.md` §5; `conductor/code_styleguides/data_oriented_design.md`. > **What this is.** Manual Slop has two patterns for "turning a feature on or off": (a) file presence (the file is the switch; `rm` to turn off); (b) config flag (the `[ai_settings.toml]` toggle or the GUI checkbox). They're both valid; each is right in different contexts. This styleguide codifies when to use which. --- ## 0. The two patterns (the one-glance table) | Pattern | How it works | How to turn off | How to turn on | |---|---|---|---| | **File presence** | The feature checks for the file's existence; the file is the switch | `rm ` | Touch the file (or run the generator that creates it) | | **Config flag** | The feature checks a setting in `[ai_settings.toml]` / `[manual_slop.toml]`; the GUI checkbox is the surface | Set `enabled = false` in the config; or uncheck the GUI box | Set `enabled = true`; or check the GUI box | | **CLI flag** (a sub-pattern of config) | The CLI accepts a flag like `--no-cache`; the default behavior is "on" | Pass `--no-cache` on the CLI | Omit the flag (use the default) | | **Feature flag in metadata** (a sub-pattern) | A `metadata.json` field for the feature's track declares `uses_rag: true` | Edit the metadata | Edit the metadata | --- ## 1. When to use file presence (the "delete to turn off" pattern) **Use file presence when:** - The feature generates a *side artifact* that the user might want to *turn off* by deleting the artifact - The "off" state is *recoverable* — the artifact can be regenerated by running a command - The user *expects* to be able to manage the feature via the filesystem (the user is on the command line; they know `rm`) - The feature is *opt-in by default-off* (deleting the artifact means the feature is off; the absence of the file is the "off" state) **Examples in Manual Slop:** | Feature | The "on" state | The "off" state | The regeneration command | |---|---|---|---| | Knowledge digest injection | `~/.manual_slop/knowledge/digest.md` exists | File is deleted | `python -m src.knowledge_harvest --apply` | | Per-file knowledge for file X | `~/.manual_slop/knowledge/files/{file_id}.md` exists | File is deleted | (the next harvest regenerates) | | Saved conversations index | `~/.manual_slop/conversations/index-saved-conversations-*.json` exists | File is deleted | (n/a; user manually saves) | | RAG index for project | `~/.manual_slop/.slop_cache/chroma_/` exists | Directory is deleted | `python -m src.rag_engine --rebuild-index` | | Audit log | `~/.manual_slop/logs/sessions//comms.log` exists | File is deleted | (n/a; the log is auto-generated per turn) | **The principle (per the data-oriented foundation):** *the data is the thing*. If the feature produces a file, the file is the switch. Deleting the file is the natural way to turn off the feature. **The discovery surface:** the user can `ls ~/.manual_slop/knowledge/` and see `digest.md` (or not) and understand the state. **The ux surface:** the GUI shows the file state and provides a `[Delete to turn off]` button that does the same `rm` underneath. --- ## 2. When to use config flags (the `[ai_settings.toml]` pattern) **Use config flags when:** - The feature is *always on* by default; the flag is a way to *opt out* in special circumstances - The "off" state is *not recoverable* by a single command (it's a persistent preference) - The user *expects* to manage the feature via the GUI (they're not on the command line) - The feature's behavior is *complex* (multiple settings, not just on/off) - The setting is *user-specific* (different users might have different preferences) **Examples in Manual Slop:** | Feature | The config | The default | The GUI surface | |---|---|---|---| | RAG enabled | `[ai_settings.toml] rag.enabled` | `false` (new projects) | `[X] Enable RAG` checkbox | | RAG source | `[ai_settings.toml] rag.source` | `project` | `(project / global / none)` radio | | RAG embedding provider | `[ai_settings.toml] rag.embedding_provider` | `gemini` | dropdown | | RAG chunk size | `[ai_settings.toml] rag.chunk_size` | `1000` | integer input | | Auto-aggregate | `[ai_settings.toml] aggregate.auto_aggregate` | `true` | `[X] Auto-aggregate files` | | Force full | `[ai_settings.toml] aggregate.force_full` | `false` | `[ ] Force full content` | | Cache TTL (Anthropic) | `[ai_settings.toml] cache.anthropic_ttl_seconds` | `300` (5 min) | integer input | | Cache TTL (Gemini) | `[ai_settings.toml] cache.gemini_ttl_seconds` | `3600` (1 h) | integer input | | Knowledge harvest enabled | `[ai_settings.toml] knowledge.harvest_enabled` | `true` | `[X] Enable knowledge harvest` | | Project context file | `[manual_slop.toml] agent.context_files` | (none) | file picker | **The principle (per the data-oriented foundation):** *configuration is data*. The GUI checkbox is a *projection* of the config file; the config file is the source of truth. **The discovery surface:** the user can read `[ai_settings.toml]` and see the state. The TOML is human-readable. **The ux surface:** the GUI has a settings panel that reads from the TOML, displays it, and writes back on change. --- ## 3. When to use a CLI flag (the sub-pattern) **Use CLI flags when:** - The feature is *invoked from the command line* (not from the GUI) - The flag is a *one-shot* setting (the user doesn't want to edit a config file for a one-time run) - The default is "on" and the flag is the "off" override **Examples in Manual Slop:** | CLI | Flag | Default | Effect | |---|---|---|---| | `python -m src.knowledge_harvest` | `--apply` | off (dry-run) | Mutate: harvest + reclaim | | `python -m src.knowledge_harvest` | `--no-harvest` | off (harvest) | Reclaim only; skip LLM | | `python -m src.knowledge_harvest` | `--max-harvest-bytes N` | unlimited | Cap the conversation bytes sent to the LLM | | `python -m src.knowledge_harvest` | `--root PATH` | `~/.manual_slop` | Use a custom knowledge root | | `pytest` | `--no-header` | off | Don't print the header | | `pytest` | `-x` | off | Stop on first failure | **The principle (per the data-oriented foundation):** *the CLI flag is data*. The user types a flag; the value is passed to the function; the function behaves accordingly. --- ## 4. When to use a feature flag in `metadata.json` (the track flag) **Use metadata feature flags when:** - A track's *implementation* depends on a feature (e.g., uses RAG); this is *static* metadata about the track - The flag is *documented* in the track's `metadata.json` for reviewers - The flag is *not* a runtime setting (it doesn't change behavior at runtime; it documents intent) **Examples in Manual Slop:** ```json // In conductor/tracks//metadata.json { "uses_rag": true, "uses_mma": false, "tier": "tier-2", "uses_knowledge_harvest": true } ``` **The principle:** the metadata documents the track's dependencies. A reviewer can read the metadata to understand "this track uses RAG; if you don't have RAG enabled, the track might not work." --- ## 5. The decision tree (the 1-question test) When adding a new feature, ask this single question: ``` Q: Is the feature's "off" state recoverable by a single command? │ ├── yes (e.g., regenerate the artifact) ──► File presence │ └── no (the "off" is a persistent preference) │ ├── Q: Is the feature invoked from the CLI? │ │ │ ├── yes ──► CLI flag (sub-pattern of config) │ │ │ └── no ──► Config flag + GUI checkbox ``` **The decision is the *kind* of flag, not the *implementation*.** The file presence vs config choice is about user expectations, not technical constraints. --- ## 6. The interaction between file presence and config (the layered) **A feature can have both.** Example: - The knowledge digest is gated by **file presence** (`digest.md` exists) for the *injection* of the `{knowledge}` block. - The knowledge harvest is gated by **config** (`[ai_settings.knowledge] harvest_enabled = true`) for the *automatic regeneration* of the digest after a discussion ends. **The two flags are layered:** - File presence controls *whether the digest is injected* (a per-turn decision) - Config flag controls *whether the digest is regenerated* (a per-discussion decision) **The user can turn off the entire feature** by both `rm digest.md` AND setting `harvest_enabled = false`. The feature is fully off. **The user can turn on a single layer** by: - `touch digest.md` to turn on injection (but the file is empty; the next harvest populates it) - Setting `harvest_enabled = true` to turn on auto-regeneration **The GUI surface** (per layer) is separate: - The `Knowledge` panel shows the digest file state and provides `[Delete to turn off]` and `[Regenerate]` buttons - The `AI Settings > Knowledge` panel has the `harvest_enabled` checkbox **The ux:** the user has *two* knobs (file presence for "what's injected now"; config for "what gets regenerated"). Each is explicit about what it controls. --- ## 7. The forbidden patterns (the "don't do this" list) | Pattern | Why it's forbidden | |---|---| | File presence for a feature with no regeneration path | The user can't turn the feature back on without manual intervention | | Config flag for a side artifact | The user can't `rm` the artifact to clean up disk | | File presence *and* config flag for the *same* behavior | Confusing; the user doesn't know which to use | | CLI flag that has no default ("off" by default) | The user has to remember the flag every time | | GUI checkbox that doesn't write to the config file | The change is lost on restart | | `metadata.json` flag that changes runtime behavior | The metadata is for documentation, not for behavior | | Hidden file (in `~/.cache/` or `/tmp/`) as a flag | The user can't find it | | Symlink-based flag | Platform-specific; debugging nightmare | | Env var as the only flag | The user can't discover it via the GUI or the docs | --- ## 8. The cross-references - `conductor/code_styleguides/knowledge_artifacts.md` §5 — the knowledge digest "delete to turn off" example - `conductor/code_styleguides/data_oriented_design.md` §1.2 — "Design around a model of the world" (the anti-pattern) - `conductor/code_styleguides/cache_friendly_context.md` — the cache TTL GUI surface (a config flag + GUI checkbox) - `conductor/code_styleguides/rag_integration_discipline.md` — the RAG opt-in (a config flag + GUI checkbox) - `src/paths.py` — the path resolution; the file-presence flags live under `~/.manual_slop/` - `docs/Readme.md` (human-facing) — the high-level overview - `./docs/AGENTS.md` (agent-facing) — the per-tier reading path