Analysis of src/kiss/SYSTEM.md

A line-by-line audit of the KISS Sorcar system prompt (version 2026.8.8, 188 lines): which instructions conflict with each other, which are ambiguous or impossible to obey, which are structurally broken — and how to rewrite the prompt so that any LLM can follow it deterministically.

Contents

  1. Summary of findings
  2. Part 1 — Conflicting or mutually straining instructions (12 findings)
  3. Part 2 — Ambiguous or underspecified instructions (11 findings)
  4. Part 3 — Structural defects and omissions (7 findings)
  5. Part 4 — How to redesign the prompt for near-100% compliance
  6. Part 5 — Worked example: three rules rewritten

1. Summary of findings

The prompt is thorough and covers real failure modes (background-process deadlock, stale training data, temp-file litter), but it has three systemic problems that prevent reliable compliance:

  1. No precedence hierarchy. At least 11 rule pairs give contradictory orders with no statement of which one wins. A model facing "delete all temp files" and "maintain ./tmp/PROGRESS.md across sessions" must guess — and different models will guess differently.
  2. Quantities and triggers disagree with themselves. The summary cadence is stated three ways (every 5 steps, on multiples of 5, "last 6 steps"), the sentence budget two ways (1–10 vs. 5–10), the lint command two ways (uv run check vs. uv run check --full).
  3. The Markdown source has structural defects. Escaped tags (\<tool_rules>), an unclosed <identity> element, a (c) that became a copyright sign ©, and ordered lists whose items are all written as "1." in the raw text — the text an LLM actually reads — so the instruction "go to 4" points at no visible step number and must be resolved by counting.
Findings by category (30 total) Conflicts & tensions 12 Ambiguities 11 Structural defects & omissions 7 Each finding below quotes the exact prompt text it refers to.

2. Part 1 — Conflicting or mutually straining instructions

Some findings below are hard contradictions (both rules cannot be obeyed at once); others are tensions — rule pairs that collide on common inputs unless the prompt supplies a scoping sentence it currently lacks. Each entry says which it is.

CONFLICT 1Delete every temp file vs. maintain PROGRESS.md across sessions

Pre-Finish: "You MUST delete every temporary file you created in ./tmp/ during this session … Do NOT call finish(success=True) while any temp file you created still remains."
Sorcar-specific: "MAINTAIN a ./tmp/PROGRESS.md across agent sessions, logging details of all the steps you have done so far from the start."

Hard contradiction. A file cannot simultaneously persist across sessions and be deleted at the end of every session. A related risk (weaker, because cleanup formally applies only to finish(success=True)) touches ./tmp/ideas.md and ./tmp/explored-ideas.md: the AI-discovery workflow consults them in later iterations ("exclude ideas that have been explored in ./tmp/explored-ideas.md"), which fails if a completed earlier task in the same effort already deleted them.

Fix: add an explicit exemption list: "Delete every temp file you created, except PROGRESS.md, ideas.md, and explored-ideas.md, which persist across sessions. Delete those three only on finish(success=True, is_continue=False)."

CONFLICT 2"Run only the impacted tests" vs. "fix all errors including pre-existing ones"

Testing: "After modifications, run only the impacted tests."
Testing: "Run lint and typecheckers; fix all errors including pre-existing ones." / Pre-Finish: "run uv run check --full and fix all errors including pre existing ones."

Scope tension, not a hard contradiction. A full lint/typecheck pass is compatible with running only impacted tests — they are different activities — but the prompt never draws that line, and "fix all errors including pre-existing ones" reads naturally as covering test failures too. Read that way, discovering pre-existing failures requires running everything, which "run only the impacted tests" forbids. The obligation also pulls against "Your sole goal is completing the user's task": repairing unrelated pre-existing failures can dwarf the actual task, and the prompt gives no stopping criterion.

Fix: separate the scopes: "During development, run only impacted tests. Before finishing, run the full lint/typecheck pass (uv run check --full) and fix every error it reports, even pre-existing ones. Do not fix pre-existing test failures unrelated to your change; report them instead."

CONFLICT 3"No mocks, ever" vs. "100% branch coverage"

"Aim for 100% branch coverage on new and modified code." … "Write end-to-end tests only. Do not use mocks, patches, fakes, or test doubles."

Frequent practical conflict. Branches that handle rare external failures (network timeouts, disk-full, API 500s) often cannot be reached by a genuine end-to-end test. Whenever code contains such branches — which is most non-trivial code — the two rules cannot both be satisfied, and a model must silently violate one of them. Note also the strength mismatch: coverage is soft ("Aim for") in one line and hard ("MANDATORY … tests with 100% coverage") six lines later.

Fix: pick one strength and add an escape hatch: "Cover every branch reachable without test doubles; for unreachable error-handling branches, document why in the test file."

CONFLICT 4Docstrings required vs. documentation forbidden

"Public methods must have full docstrings." … "Write documentation only when the task explicitly requires it."

Docstrings are documentation. A literal-minded model asked to add a public method to a task that never mentions documentation receives two contradictory orders.

Fix: "Public methods must have docstrings. Do not write separate documentation files (README, guides, changelogs) unless the task asks."

CONFLICT 5Ambiguity: ask the user, or search the internet?

Identity: "If there is ambiguity or under-specification in the user task, search the internet to find the most reliable and modern solution to resolve the ambiguity."
Workflow: "If referenced files, commands, or config don't exist, stop and ask the user rather than guessing."

Both rules trigger on under-specification, and they prescribe opposite actions. The prompt never says which kinds of ambiguity go to the internet and which go to the human.

Fix: a two-branch rule: "If the ambiguity is about facts or best practices → research. If it is about the user's intent or missing project artifactsask_user_question."

CONFLICT 6Summary cadence: every 5 steps, or the last 6 steps?

SYSTEM.md: "you MUST call summary(…) after EVERY 5 steps of work" … "in 1-10 structured sentences"
Outside the file, the summary tool description says "MANDATORY every 5 steps: summarize your last 6 steps of work", and the runtime reminder that enforces the rule asks for "5-10 sentences".

Cross-source inconsistency. The prompt, the tool description, and the runtime reminder each state the cadence and sentence budget differently (5 steps vs. "last 6 steps"; 1–10 vs. 5–10 sentences). The prompt also encourages batching independent tool calls in one block but never defines how batched calls interact with the step counter — if the runtime ever advances the counter past a multiple-of-5 boundary in one batch, the stated trigger ("whenever the counter shows 4, 9, 14 …") has no defined behavior.

Fix: one number, one trigger, generated into all three places from a single source, plus an explicit sentence on how batched calls advance the counter.

CONFLICT 7"Every task" vs. "project-related tasks" for the mandatory first action

Heading: "Mandatory First Actions for project-related tasks" — Body: "Your VERY FIRST tool call in every task MUST be Read('./SORCAR.md')."

The heading scopes the rule to project tasks; the body universalizes it. For a pure question-answering task ("what's the weather?"), the two readings prescribe different first actions. "Project-related" is itself never defined.

Fix: make heading and body agree, and define the scope: "In every task whose working directory contains SORCAR.md, your first call must be Read('./SORCAR.md')."

CONFLICT 8Two different lint commands

Sorcar-specific: "Lint/typecheck/format: uv run check." — Pre-Finish: "you MUST run uv run check --full".

Missing scoping, likely intended as two modes. The two commands plausibly serve different purposes (quick iteration vs. exhaustive pre-finish pass), but the prompt never says so — the Sorcar-specific line presents uv run check as the lint command without qualification. A model that runs it at finish time has, by the Pre-Finish sentence, violated a MUST.

Fix: state both with scopes: "uv run check for quick iteration; uv run check --full exactly once before finish."

CONFLICT 9HTML-only output vs. Markdown-only output

"Compose the full detailed answer … always formatted as HTML … never Markdown." vs. summary tool: "written in Markdown format with bullet lists."

Not a contradiction — a leakage risk. The two rules govern different tool fields (finish.summary_in_html vs. summary.description) and can both be obeyed. The problem is the absolute wording "never Markdown", stated without its scope, which primes weaker models to apply it everywhere. Absolutes stated without scope routinely leak across contexts.

Fix: attach the scope to the absolute: "finish.summary_in_html: HTML only. summary.description: Markdown only."

CONFLICT 1010 websites vs. 1 website

"Visit at least 10 distinct websites per research session … a hard requirement." vs. Real-Time Data: "You can visit ONLY 1 website instead of 10."

Many queries are both research and time-sensitive — "what is the current stable version of Node and how do I migrate?" involves a fact that changes weekly (1-site rule) inside a best-practices question (10-site rule). No tie-breaker is given. "ONLY 1" is also ambiguous between exactly one, at most one, and one is enough.

Fix: "For a pure real-time datum (price, score, weather), one authoritative site suffices. If the task mixes real-time data with research questions, the 10-site rule governs the research part."

CONFLICT 11Read-before-modify covers Edit but not Write

"You MUST call Read(file_path) on every file BEFORE calling Edit(file_path) on it." … "Use Write() for new files; Edit() for small changes."

Loophole rather than contradiction. Write() can silently overwrite an existing file, and no rule requires reading it first. A model can lawfully destroy a file it has never seen — the exact accident the read-before-modify rule exists to prevent. The rule guards the small door and leaves the big one open.

Fix: "Read every existing file before modifying it with either Edit or Write. Write without a prior Read is allowed only for files that do not yet exist."

CONFLICT 12Mandatory multi-file organization vs. "simple and minimal"

"Organize code across multiple files grouped by functionality." … "Before writing code, ask: is this simple, elegant, general, and minimal?"

Tension on small inputs. For a small utility or a single-purpose script, splitting code across multiple files is the opposite of simple and minimal — yet the multi-file rule is stated unconditionally, with no size threshold at which it activates. A literal model writing a 40-line tool must either violate the organization rule or manufacture artificial modules.

Fix: add the threshold: "Split code into multiple files by functionality once a module exceeds roughly N lines or two unrelated responsibilities; below that, one file is correct."

3. Part 2 — Ambiguous or underspecified instructions

AMBIGUOUS 1"AI slop" is never defined

"produce ONLY highest-quality work with NO AI SLOP. Check and remove AI slop after the task is done."

The phrase appears three times and carries a MUST-strength obligation, yet the prompt never says what counts as slop. Different models will remove different things — some will strip useful hedging, others will leave filler intact.

Fix: define it operationally: "AI slop = filler phrases ('delve', 'It's important to note'), unrequested caveats, generic bullet padding, emoji decoration, repeated restatement of the question, and boilerplate conclusions."

AMBIGUOUS 2The step counter's meaning is guessed, not stated

"every tool result shows your current step count (e.g. 'Steps: 12/100') … whenever the counter shows 4, 9, 14, …, your VERY NEXT tool call MUST be summary."

Is "Steps: 12" the number of steps completed or the index of the current step? The rule's arithmetic ("shows 4 → next call is step 5") assumes completed-count semantics but never says so. An off-by-one here means every summary lands on the wrong step for the whole task.

Fix: one sentence: "The counter shows steps already completed; the next tool call is step N+1." Plus a two-line worked example.

AMBIGUOUS 3finish() parameter combinations are undefined

"Call finish(is_continue=True) to pause and resume the task in a new context."

The finish tool requires a success argument, but the pause instruction omits it. What does success=True, is_continue=True mean? Is it legal? The prompt never enumerates the valid combinations, so each model invents its own convention.

Fix: a three-row table: (True, False) = done; (False, True) = pause and resume; (False, False) = failed and giving up. Mark (True, True) invalid.

AMBIGUOUS 4"cores − 2" has no floor

"split the set of tests equally by the number of test methods into the number of cores -2 and run all splits in parallel."

On a 1- or 2-core machine this yields zero or minus-one splits. No floor, no fallback. It is also unclear whether "cores" means physical or logical, "equally by the number of test methods" is undefined when the count does not divide evenly, and the rule collides with "run only the impacted tests" whenever the impacted set is a whole folder.

Fix: "Use max(1, cores − 2) splits, where cores comes from the number_of_cores tool; distribute test methods round-robin so split sizes differ by at most one."

AMBIGUOUS 5Detecting spoken input is impossible from text

"their spoken words arrive as text input to the task. When a user speaks to you, you MUST respond back … using the talk tool … Distinguish between different users using voice recognition."

If speech arrives as plain text, the agent has no signal to distinguish typed from spoken input — yet the MUST fires only for spoken input. And an LLM receiving text cannot perform "voice recognition" at all; that instruction is unsatisfiable as written.

Fix: either tag spoken input mechanically ("spoken input arrives prefixed with [voice:user-3 lang=en-US] — respond via talk()") or drop the distinction.

AMBIGUOUS 6"add the directory contents to git" — which directory, commit or stage?

"If you create any artifact that the user can use after the task is over, you MUST create them in a directory and add the directory contents to git."

Every file is "in a directory," so the first clause is vacuous. Does "add to git" mean git add (stage) or add-and-commit? Which artifacts qualify — is an HTML report an artifact? The neighbouring rule that worktrees "are discarded after a task" raises the stakes: if staging isn't enough to survive the discard, a wrong guess loses the user's deliverable.

Fix: state precisely which git operation preserves files across worktree disposal in this framework, and name the target directories: "Place deliverables under ./reports/ or ./artifacts/ and run <the exact command>; anything short of that is lost when the worktree is discarded."

AMBIGUOUS 7"You MUST do the same for any feature implementation"

"MANDATORY (MUST FOLLOW): Reproduce any issue by writing real end-to-end tests with 100% coverage. Then fix the issue. You can use screenshots to validate the implementation. You MUST do the same for any feature implementation."

"The same" has three possible antecedents: write end-to-end tests, achieve 100% coverage, or use screenshots. A feature cannot be "reproduced" the way a bug can, so the referent must be partial — but which part is mandatory is left to inference.

Fix: "For every new feature, write end-to-end tests covering its behavior before finishing." (One sentence, no pronoun.)

AMBIGUOUS 8The race-condition sleep: in the test or in the source?

"To confirm race conditions: add a random sleep (\<0.1s) before the suspected racing statements."

"Racing statements" live in production code. Does the model temporarily instrument the source (then it must remember to revert — not stated), or perturb timing from the test side? The escaped \< also renders literally, garbling the threshold.

Fix: "Temporarily insert a random sleep (< 0.1 s) before the suspected statements in the source, confirm the failure, then remove the sleep before committing."

AMBIGUOUS 9"extract information … without deep thinking"

Web-research step 2: "(b) extract information needed for the task without deep thinking, © use Edit() to append …"

"Without deep thinking" is unmeasurable — models cannot verify their own thinking depth. The intent (don't synthesize until all 10 sites are visited) is stated better two lines later, making this clause pure noise. Note also the corrupted "©" where "(c)" was meant.

Fix: delete the clause; "Do not synthesize until the counter reaches 10" already carries the intent.

AMBIGUOUS 10"open a random keyword search"

"If Google search is blocked, open a random keyword search in the Chromium browser, and ask the user to manually pass the bot check."

Unclear on every axis: random keywords about what? In which engine? Why random rather than the actual query? The apparent intent — trigger the CAPTCHA on a throwaway query so the user can clear it — is never stated, so the step reads as nonsense to a model that can't guess it.

Fix: "If Google blocks you, load any Google search page so its bot check appears, call show_browser(), and ask the user to solve it; then retry your real query."

AMBIGUOUS 11The research procedure's Edit() calls vs. the read-before-Edit rule

Web research: "use Edit() to append … use Edit() to update the header counter" — Workflow: "You MUST call Read(file_path) on every file BEFORE calling Edit(file_path) on it. Never Edit a file you have not Read in the current session."

The 10-site procedure prescribes two Edit() calls per site on the research log but never mentions Read(). A model applying the NON-NEGOTIABLE read-before-Edit rule literally must interleave a Read before each Edit (20 extra calls per session), or decide on its own that having just written the file counts as having read it — a judgment the prompt does not license.

Fix: one clarifying clause on the read-before-Edit rule: "A file you created with Write() in this session counts as read."

4. Part 3 — Structural defects and omissions

DEFECT 1Ordered lists written as "1. 1. 1." — and a jump target that must be inferred

The Markdown source numbers every list item 1. in the AI-discovery workflow, Complex Task Planning, and Pre-Finish sections. A Markdown renderer renumbers these to 1, 2, 3 for human readers — but the LLM consumes the raw text, where every step is labeled "1." The AI-discovery instruction "go to 4" therefore points at no visibly numbered step; the model must reconstruct ordinals by counting items, an inference step that weaker models will get wrong inside a MANDATORY procedure.

Fix: number lists explicitly (1, 2, 3 …) in the source, or replace positional jumps with named ones ("return to the pairwise-judging step").

DEFECT 2Escaped and unbalanced section tags

Sections open and close inconsistently: \<tool_rules>, \<web_research>, and \<code_style> are backslash-escaped while <workflow>, <testing>, and <identity> are not — and <identity> is never closed. Models use these tags to scope rules; unbalanced tags make the identity section appear to swallow the whole document, and escaped ones may not register as structure at all.

Fix: use unescaped, balanced XML-style tags throughout, one opening and one closing per section.

DEFECT 3Web-research rules living inside the visibility-constraint block

Inside \<visibility_constraint> … "If there is ambiguity … search the internet …" / "Use Google search on the Internet extensively for all tasks …"

Two research-policy bullets sit inside the block about what the user can see. A model that scopes rules by section will underweight or miss them; a model that reads linearly will wonder why output-visibility constraints suddenly discuss Google.

Fix: move both bullets into the web_research section.

DEFECT 4Typos and mojibake in normative text

"Be honest,direct" (missing space); "©" for "(c)"; "pre existing" vs. "pre-existing" in the same rule stated twice; "\<0.1s" with a stray backslash. Individually cosmetic — but they appear inside MUST-level rules, and garbled MUSTs get quietly deprioritized by models trained to trust well-formed text more.

Fix: proofread pass; lint the prompt file itself in CI so regressions are caught.

DEFECT 5The same rule stated twice with different words

"Fix all errors including pre-existing ones" appears in both Testing and Pre-Finish (with different lint commands — see Conflict 8). "Check and remove AI slop" appears three times. The summary cadence is specified in two places (prompt + tool description) that disagree. Duplication is how contradictions are born: each copy drifts independently.

Fix: one rule, one home. If a rule must be echoed elsewhere, echo by reference ("see Pre-Finish step 2"), never by paraphrase.

DEFECT 6No priority order across rule sources

SORCAR.md must be followed "with highest priority"; the summary rule "cannot be overridden by the user task"; everything else floats. When the user's task, SORCAR.md, and SYSTEM.md disagree (as real tasks routinely make them do), the model has no documented resolution order — the single largest cause of divergent behavior across LLMs.

Fix: open the prompt with an explicit hierarchy, e.g.: safety > non-overridable SYSTEM rules (enumerated) > user task > SORCAR.md > remaining SYSTEM defaults — and mark every rule with its tier.

DEFECT 7High-impact capabilities with no authorization guardrails

"You can do software development, control a computer, … shop, bank, message, email, browse …" — "Authenticate unauthenticated third-party agents … You MUST collect any security or authentication code or token without user's help if possible."

The prompt grants the agent banking, shopping, messaging, emailing, and device control, and even instructs it to obtain security codes and tokens autonomously — yet it contains no confirmation tier, no spending or scope limits, no irreversibility check, and no rule for when an action requires explicit user approval. For an instruction set that demands precision everywhere else, the highest-consequence actions are the least constrained. This is an omission rather than a conflict, but it is the gap most likely to produce a harmful divergence between two models reading the same prompt.

Fix: add an authorization section: enumerate action classes (read-only, reversible-write, irreversible/financial/messaging), require ask_user_question() confirmation before the irreversible class, and scope the token-collection rule to accounts the user has already connected.

5. Part 4 — How to redesign the prompt for near-100% compliance

No prompt achieves literal 100% compliance from every model — but the gap between a prompt models mostly follow and one they follow almost always comes down to seven engineering practices. Honesty note: "100% of the time" is not achievable for any prompt across all LLMs; the practices below maximize the probability of compliance and make violations detectable.

#PracticeWhat it fixes here
1Declare a precedence hierarchy first. Number the tiers; tag every rule with its tier. Conflicts then resolve mechanically instead of by model temperament.Defect 6, Conflicts 1–5
2One rule, one home, one number. Every quantity (5 steps, 10 sites, 0.1 s, cores − 2) appears exactly once; other mentions link to it. Tool descriptions must be generated from the same source as the prompt so they cannot drift. Conflicts 6, 8; Defect 5
3Write rules as guarded commands: WHEN <objective condition> DO <single action> UNLESS <named exception>. "When in doubt, search" is a mood; "IF the task names any library version, THEN research" is a test the model can run on itself. Ambiguities 5, 7, 9, 10
4Specify every edge case a rule creates. Cores ≤ 2, tasks shorter than 5 steps, batched tool calls skipping a multiple of 5, files that exist when Write() is called, finish() during a continuation. Each rule's author should ask: what inputs make this rule undefined?Conflicts 6, 11; Ambiguities 2, 3, 4
5Define every judgment word or delete it. "AI slop," "project-related," "impacted tests," "deep thinking," "artifact" — each needs either an operational definition (a checklist the model can apply) or removal. Ambiguities 1, 6, 9
6Keep the source machine-valid. Balanced unescaped tags, real ordinal numbering, no mojibake. Run the prompt file through a linter in CI; a broken "go to 4" should fail the build, not confuse the agent.Defects 1–4
7Add worked examples to every counting rule. One two-line trace ("counter shows 9 → your next call is step 10 → it must be summary(…)") eliminates more off-by-one violations than three paragraphs of prose.Ambiguity 2, Conflict 6

6. Part 5 — Worked example: three rules rewritten

REWRITEThe summary cadence rule

## Progress summaries (tier 1 — cannot be overridden by the user task)

Every tool result ends with "Steps: N/M". N = tool calls already completed.

RULE: if N is 4, 9, 14, 19, … (N mod 5 = 4), your next tool call MUST be
summary(description=<Markdown, 3-8 bullet points recapping work since the
previous summary>). All other calls on that step are rejected.

EDGE CASES:
- If a batched block of calls jumps N past a multiple-of-5 boundary, call
  summary as your first call afterward.
- finish() also counts as a tool call; if it would land on a multiple of 5,
  call summary first, then finish.

EXAMPLE: result says "Steps: 9/100" → your next call is step 10 → it must be
summary(...). After it, continue normally.

REWRITEThe temp-file cleanup rule

## Temp-file cleanup (runs before finish(success=True, is_continue=False))

DELETE: every file you created under ./tmp/ this session
        (information-*.md, file-information-*.md, scratch scripts, downloads).
KEEP:   ./tmp/PROGRESS.md, ./tmp/ideas.md, ./tmp/explored-ideas.md — these
        persist across sessions by design.
KEEP:   everything you did not create.
SKIP:   the whole cleanup when calling finish(is_continue=True).

VERIFY: run `ls ./tmp` and confirm only KEEP-listed files remain.

REWRITEThe research-trigger rule

## When to research (decision procedure — evaluate top to bottom, first match wins)

1. Task asks for a real-time datum (price, score, weather, headline)
   → visit 1 authoritative site via go_to_url(); never answer from memory.
2. Task depends on an external API, library version, tool behavior, or any
   fact that may postdate training → full research session: 10 distinct
   sites via go_to_url(), logged in ./tmp/information-{id}.md.
3. Task is about the user's intent, or refers to files/commands that do not
   exist → ask_user_question(); do not guess, do not research around it.
4. Task is fully specified by local files you have read (mechanical edit,
   arithmetic, refactor) → no research.

Prepared from a full read of src/kiss/SYSTEM.md (188 lines, version 2026.8.8). Quoted passages appear verbatim in that file except where explicitly labeled as coming from a tool description or runtime reminder. Findings were independently re-verified against the source by a second model in a read-only review pass before publication.