6 Commits
Author SHA1 Message Date
Gabriel Brown 9b06e9e24b Docs: Add a spelling rule to unslop
American spelling is the default and British forms turn up in generated
prose. Catch the common endings and the irregulars, with two exceptions:
project vocabulary that the client's documents, ticket titles and codebase
all spell the British way, such as "enrolment" on APSCA, and existing code
identifiers, which are never renamed to fix spelling.

The rules after it shift by one.
2026-09-18 17:28:56 -04:00
Gabriel Brown 59da2bb2fc Docs: Scope the Ksense sections to the Ksense folder
The merge request conventions and the coworker list only apply to Ksense
work, but they load in every project including personal ones. Name the
folder that work lives in so an agent reads those sections as conditional
rather than as always in force.
2026-09-18 17:28:56 -04:00
Gabriel Brown 5ebecd59bb Register Atlassian's MCP server
Jira and Confluence reached Claude Code through two claude.ai connectors,
which are configured per account rather than per machine and had been added
twice. Atlassian hosts its own MCP server, so it belongs in this list with
the others and a new machine picks it up from the installer.

It carries no token. The server runs its own OAuth and Claude Code signs in
through /mcp on first use.
2026-09-18 17:28:56 -04:00
Gabriel Brown 501f7306ed Point every ssh host at the desktop keyring agent
Claude Code and Codex start their shells without SSH_AUTH_SOCK. id_ed25519
has a passphrase, so batch ssh from a harness had no way to unlock it and
failed with "Permission denied (publickey)" against server.gib, junior.gib
and git.gbrown.org. The key and the per-host blocks were right the whole
time, which made it read as a key problem and cost several rounds of
checking keys that were never wrong.

The desktop keyring agent at $XDG_RUNTIME_DIR/keyring/ssh already holds the
key unlocked for the interactive session. A Host * block with IdentityAgent
points every host at that socket, so a shell that inherits no agent gets the
same one the terminal uses.
2026-09-18 17:28:56 -04:00
gibandClaude Opus 5 130137485e Guard the mesa driver swap on its end state
mesa-va-drivers-freeworld Provides mesa-va-drivers, so once the swap has run
once it becomes the only thing providing the name we ask dnf to remove. The
command then resolves to removing and installing the same package in a single
transaction and exits with "conflicting requests", which reported
install-packages as a failed stage on every run after the first even though
the machine was already in the desired state.

The failure also produced misleading output, because dnf explored removing
mesa-dri-drivers and surfaced unrelated complaints from steam, lutris and
tigervnc-server-common.

Check for the freeworld package with rpm -q and skip the swap when it is
already installed.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01TFG55mJBiH2tV38tXcNzJ9
2026-09-18 11:02:35 -04:00
Gabriel Brown 5ebebc8aa2 Docs: Treat the pre-MR audit verdict as the gate and converge reruns with context 2026-09-17 11:43:07 -04:00
6 changed files with 72 additions and 15 deletions
+9
View File
@@ -1405,8 +1405,17 @@ soft "the multimedia group update" \
sync sync
log "Swapping ffmpeg-free for ffmpeg" log "Swapping ffmpeg-free for ffmpeg"
soft "the ffmpeg swap" sudo dnf swap -y 'ffmpeg-free' 'ffmpeg' --allowerasing soft "the ffmpeg swap" sudo dnf swap -y 'ffmpeg-free' 'ffmpeg' --allowerasing
# mesa-va-drivers-freeworld Provides mesa-va-drivers, so once the swap has been
# done it is the only thing providing the name we ask dnf to remove. `dnf swap`
# then resolves to removing and installing the same package in one transaction
# and fails with "conflicting requests", which reports install-packages as a
# failed stage on every subsequent run. Guard on the end state instead.
if rpm -q mesa-va-drivers-freeworld >/dev/null 2>&1; then
log "mesa-va-drivers-freeworld is already installed; swap not needed"
else
log "Swapping mesa-va-drivers for mesa-va-drivers-freeworld" log "Swapping mesa-va-drivers for mesa-va-drivers-freeworld"
soft "the mesa driver swap" sudo dnf swap -y mesa-va-drivers mesa-va-drivers-freeworld soft "the mesa driver swap" sudo dnf swap -y mesa-va-drivers mesa-va-drivers-freeworld
fi
log "Upgrading Multimedia group with optional packages" log "Upgrading Multimedia group with optional packages"
soft "the optional Multimedia upgrade" sudo dnf4 group upgrade -y --with-optional Multimedia soft "the optional Multimedia upgrade" sudo dnf4 group upgrade -y --with-optional Multimedia
log "Installing GStreamer plugins (bad, good, base)" log "Installing GStreamer plugins (bad, good, base)"
+2
View File
@@ -2,6 +2,8 @@ I'm Gabriel. You're my agent. We will be working together a lot, so I thought I
I'm a software developer at Ksense Technology Group. At Ksense, we basically sell our services as developers to clients to create web applications or web servers. Basically whatever the client wants, but for the most part, we create web applications with Next.js. I am the primary developer for internal tools & web applications. I mainly work on an application called Command Center, which serves as a portal for our project managers to interact with our clients. I'm a software developer at Ksense Technology Group. At Ksense, we basically sell our services as developers to clients to create web applications or web servers. Basically whatever the client wants, but for the most part, we create web applications with Next.js. I am the primary developer for internal tools & web applications. I mainly work on an application called Command Center, which serves as a portal for our project managers to interact with our clients.
My Ksense work lives in ~/Documents/Code/Ksense. The Ksense-specific sections below (Merge Requests, Coworkers) mostly matter when I am working inside that folder. Anywhere else, assume a personal project.
I love to build. I focus on building complex things as simple as possible. I love to find ways to reduce complexity when solving problems. I love to build. I focus on building complex things as simple as possible. I love to find ways to reduce complexity when solving problems.
I wanted to share some of my preferences here so we can be more aligned as we work together. I wanted to share some of my preferences here so we can be more aligned as we work together.
+4
View File
@@ -19,3 +19,7 @@ nanokvm-mac http https://macnano.gbrown.org/api/mcp NANOKVM_MAC_TOKEN
# Bill Tracker's hosted MCP server. No token: it is an OAuth server of its own # Bill Tracker's hosted MCP server. No token: it is an OAuth server of its own
# and Claude Code signs in through Gib's Auth on first use. # and Claude Code signs in through Gib's Auth on first use.
bill-tracker http https://mcp.billtracker.gbrown.org/mcp bill-tracker http https://mcp.billtracker.gbrown.org/mcp
# Atlassian's hosted MCP server for Jira and Confluence. No token: it is an
# OAuth server and Claude Code signs in through /mcp on first use.
atlassian http https://mcp.atlassian.com/v1/mcp
+32 -1
View File
@@ -751,6 +751,35 @@ Entered only when the user has confirmed (per Phase 0) that the plan is approved
write `mr.md` before that verdict is reached. write `mr.md` before that verdict is reached.
Findings that need no code change (mentions, disclosures) get addressed in Findings that need no code change (mentions, disclosures) get addressed in
`mr.md`'s Additional Notes or the Jira fields as usual. `mr.md`'s Additional Notes or the Jira fields as usual.
**The verdict is the gate and it is not negotiable.** Ready to Open MR is what
goes on record with the Lead, so never reason your way past it because the
remaining items look harmless. That judgment is not yours to make.
**Don't confuse the verdict with the handoff's recommendation.** They are
different fields in different files for different readers. The audit's
`Verdict` says whether the branch is ready to become an MR, and that is the
gate. The handoff's `Recommendation` (`Merge`, `Merge after conditions`) is
advice to the maintainer about merging it, and `Merge after conditions` is
normal and expected at a Ready verdict. Never treat the recommendation as a
blocker or report it as one.
**Reruns converge by giving the audit more, not by repeating the command.**
When a rerun is needed, the user is running it, so every rerun costs them.
Make each one count:
- **Feed it context on the first run.** It reviews the diff, and left alone it
re-derives intent from the branch name and re-raises decisions that are
already settled. Ask the user to point it at the ticket's
`resources/ticket.md` and `plan.md`. This is the cheapest thing that reduces
repeat findings.
- **Answer its decisions explicitly in the rerun.** When it parks a finding
under "Decide before opening", write the decision and its reasoning into the
prompt for the next run, so it can reclassify rather than re-ask. A silent
rerun on an unchanged diff re-asks the same question.
- **Say so when it finds new things in unchanged code.** That means the earlier
run was an incomplete pass, not that the branch got worse. Tell the user
plainly, because it is the audit's problem to fix and it changes how much
weight the next run deserves.
8. Read `~/.agents/skills/ticket/templates/mr.md` — this is the org's MR template, 8. Read `~/.agents/skills/ticket/templates/mr.md` — this is the org's MR template,
copied into this skill so it still works even though the original copied into this skill so it still works even though the original
`.claude/docs/mr/template.md` no longer exists in the command-center repo. `mr.md` `.claude/docs/mr/template.md` no longer exists in the command-center repo. `mr.md`
@@ -775,7 +804,9 @@ Entered only when the user has confirmed (per Phase 0) that the plan is approved
verified" if you actually ran a build and it passed). verified" if you actually ran a build and it passed).
- Replace `<!-- Paste the Pre-MR handoff here -->` with the exact content of the - Replace `<!-- Paste the Pre-MR handoff here -->` with the exact content of the
latest `pre-mr-review` handoff file (the one with verdict Ready to Open MR) — latest `pre-mr-review` handoff file (the one with verdict Ready to Open MR) —
paste it verbatim, don't summarize it. paste it verbatim, don't summarize it. Its `Recommendation` line is the
audit's advice to the maintainer and is left exactly as written, including
`Merge after conditions`.
The handoff section of `mr.md` is GENERATED OUTPUT, not something you author. The handoff section of `mr.md` is GENERATED OUTPUT, not something you author.
It is the block that states whether the branch is ready to merge, so it must be It is the block that states whether the branch is ready to merge, so it must be
+16 -12
View File
@@ -55,26 +55,30 @@ Removing patterns is half the job. Sterile, voiceless writing is just as obvious
18. **Decorative emojis.** Remove from headings and bullets. 18. **Decorative emojis.** Remove from headings and bullets.
19. **Curly quotes.** Replace with straight quotes. 19. **Curly quotes.** Replace with straight quotes.
### Spelling
20. **British spelling.** The author is American. Catch -our (behaviour, flavour, colour, favour, honour), -ise and -ised (recognise, organise, authorise, prioritise, summarise, initialise), -yse (analyse), -re (centre, metre), -logue (catalogue, dialogue), doubled l (travelling, labelled, modelling), and the odd ones (licence as a noun, judgement, programme, grey, whilst). Fix them to the American form. Two exceptions: a word that is the project's own established vocabulary, spelled that way in the client's documents, the ticket titles and the codebase alike (on APSCA, "enrolment" and "cancelled"), and an existing code identifier, enum value, event type or template key, which is never renamed to fix spelling. Check the codebase once before deciding a word is project vocabulary, and do not flip it back and forth.
### Communication artifacts ### Communication artifacts
20. **Chatbot phrases.** "I hope this helps!", "Let me know if...", "Of course!", "Certainly!", "Found the smoking gun!" Remove. 21. **Chatbot phrases.** "I hope this helps!", "Let me know if...", "Of course!", "Certainly!", "Found the smoking gun!" Remove.
21. **Cutoff disclaimers.** "While specific details are limited..." Find sources or remove. 22. **Cutoff disclaimers.** "While specific details are limited..." Find sources or remove.
22. **Sycophantic tone.** "Great question! You're absolutely right!" Respond directly. 23. **Sycophantic tone.** "Great question! You're absolutely right!" Respond directly.
### Filler ### Filler
23. **Filler phrases.** "In order to" becomes "To". "Due to the fact that" becomes "Because". "It is important to note that" gets deleted. 24. **Filler phrases.** "In order to" becomes "To". "Due to the fact that" becomes "Because". "It is important to note that" gets deleted.
24. **Excessive hedging.** "could potentially possibly be argued that it might" becomes "may". 25. **Excessive hedging.** "could potentially possibly be argued that it might" becomes "may".
25. **Generic conclusions.** "The future looks bright." State specific plans or facts. 26. **Generic conclusions.** "The future looks bright." State specific plans or facts.
### Jargon ### Jargon
26. **Abstract metaphor nouns.** Substrate, wedge, vector, locus, vantage, nexus, primitive (as noun), harness (as metaphor), surface (as in "API surface"), bedrock, scaffolding (as metaphor), modality, paradigm, gold-plating, ratchet (as metaphor), evacuate (for moving code), endgame, north star, flywheel. These read as technical but usually have a plainer concrete word. "Substrate" becomes "base". "Wedge in" becomes "add". "Vector" becomes "way" or "method". "Gold-plating" becomes "more than the job needs". "Ratchet" becomes the mechanism's real name or "a limit that only tightens". "Evacuate" becomes "move out". "Endgame" becomes "the last phase". Pick the concrete word. 27. **Abstract metaphor nouns.** Substrate, wedge, vector, locus, vantage, nexus, primitive (as noun), harness (as metaphor), surface (as in "API surface"), bedrock, scaffolding (as metaphor), modality, paradigm, gold-plating, ratchet (as metaphor), evacuate (for moving code), endgame, north star, flywheel. These read as technical but usually have a plainer concrete word. "Substrate" becomes "base". "Wedge in" becomes "add". "Vector" becomes "way" or "method". "Gold-plating" becomes "more than the job needs". "Ratchet" becomes the mechanism's real name or "a limit that only tightens". "Evacuate" becomes "move out". "Endgame" becomes "the last phase". Pick the concrete word.
### Plain speech ### Plain speech
27. **Say what it does, not how it feels.** "the database stays close at hand", "SQL you can read", "types that follow your schema" name a feeling. The fix names the mechanism or a number: "`.toSQL()` returns the exact string sent to the database", "a column rename fails the build". Ask what the sentence tells the reader to do or know, then write that. If you can't restate it as a concrete instruction, fact, or number, cut it. One more check: if the sentence could appear unchanged in another project's docs, it says nothing about this one. Cut it. 28. **Say what it does, not how it feels.** "the database stays close at hand", "SQL you can read", "types that follow your schema" name a feeling. The fix names the mechanism or a number: "`.toSQL()` returns the exact string sent to the database", "a column rename fails the build". Ask what the sentence tells the reader to do or know, then write that. If you can't restate it as a concrete instruction, fact, or number, cut it. One more check: if the sentence could appear unchanged in another project's docs, it says nothing about this one. Cut it.
28. **Shorten or split dense sentences.** If the reader has to backtrack to parse a sentence, break it in two or drop clauses. One idea per sentence. 29. **Shorten or split dense sentences.** If the reader has to backtrack to parse a sentence, break it in two or drop clauses. One idea per sentence.
29. **Active voice.** Prefer it. Catch "is/are/was/were + past participle" and name the actor: "queries are validated" becomes "the compiler validates queries", "the file is parsed by the loader" becomes "the loader parses the file". Passive is fine only when the actor is unknown or genuinely doesn't matter. 30. **Active voice.** Prefer it. Catch "is/are/was/were + past participle" and name the actor: "queries are validated" becomes "the compiler validates queries", "the file is parsed by the loader" becomes "the loader parses the file". Passive is fine only when the actor is unknown or genuinely doesn't matter.
30. **Cut adverbs, or use a stronger verb.** "runs quickly" becomes "is fast" or the number. "significantly improves" becomes the measured delta. An adverb propping up a weak verb means the verb is wrong. 31. **Cut adverbs, or use a stronger verb.** "runs quickly" becomes "is fast" or the number. "significantly improves" becomes the measured delta. An adverb propping up a weak verb means the verb is wrong.
31. **Prefer the plain word.** "utilize" becomes "use", "leverage" becomes "use", "facilitate" becomes "help", "numerous" becomes "many", "in the event that" becomes "if". The fancier synonym is rarely clearer. 32. **Prefer the plain word.** "utilize" becomes "use", "leverage" becomes "use", "facilitate" becomes "help", "numerous" becomes "many", "in the event that" becomes "if". The fancier synonym is rarely clearer.
+7
View File
@@ -14,3 +14,10 @@ Host git.gbrown.org
User git User git
IdentityFile ~/.ssh/id_ed25519 IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes IdentitiesOnly yes
# Agent harnesses (Claude Code, Codex) start their shells without
# SSH_AUTH_SOCK, and id_ed25519 has a passphrase, so batch ssh from them fails
# with "Permission denied (publickey)" even though the key is right. The
# desktop keyring agent already holds the unlocked key; point every host at it.
Host *
IdentityAgent ${XDG_RUNTIME_DIR}/keyring/ssh