5.1 KiB
Documentation for agents
You MUST read each of these documents before contributing to this repository:
- Git workflow rules:
docs/agents/git-workflow.md - Repo interaction rules:
docs/agents/repo-instructions.md - Domain model & context rules:
docs/agents/domain.md
Critical Coding & Version Control Conduct
- NEVER commit directly to
masteror `testing without explicit human instruction. - NEVER merge into
masterortestingwithout explict human instruction. - ALWAYS create new branches when working on non-trivial coding tasks.
- ALWAYS commit self-contained logical unit of work.
Issues, PRs, and Comments Conduct
- ALWAYS end your written contributions with
Written by AI agent working for @jtmorris. Model: <MODEL NAME>.. Replace<MODEL NAME>with the LLM model, version, and, if relevant, number of parameters. For example:Claude Sonnet 4.7,Grok 4.3,Qwen 3.6 27B.
Critical Design Rules
1. Only Store or Cache State When It Serves a Purpose
Never store or cache state unless doing so meets at least one of:
- It is the authoritative source of truth owned by this component.
- It delivers actionable feedback that meaningfully improves the user experience or a decision.
- It provides a demonstrable and reasonably argued security or performance improvement (the burden of proof is on the proposer).
- The information cannot be obtained at the moment it is needed and keeping it produces a clear net benefit.
Storing state creates a potential disconnect with reality. Managing that disconnect requires extra tests, defensive checks, and cognitive overhead. State should be added only when the benefit is obvious and defensible.
Textbook Example (this repository – issue #11)
Proposal: run which tailscale at startup, set a binaryAvailable boolean, and guard every tailscale invocation behind it.
Why this was harmful
- Wrong solution to the actual problem. This project is a GUI wrapper around the
tailscalebinary. If the binary doesn’t exist, there is nothing to do except surface an error. Storing a flag and guarding UI actions adds state for no gain. - Creates a new class of edge cases that must be tested: the binary existed when the flag was set but later disappears. The code must now defend against both “flag is false” and “flag is wrong.”
- Unreliable guard for a failure the code must handle anyway. A missing binary produces a clear exit-code failure on the real command. Checking the flag and handling the failure duplicates work. Reference: #11.
Code Style Guidance
1. NEVER Write Conditional and Loop Blocks Without Curly Braces
ALWAYS use curly braces, {}, for if, else, while, and for blocks, even when they contain only a single statement. This ensures that any future additions to the block remain within the intended control flow. Reference: CVE-2014-1266.
GOOD Examples:
if (myvar) {
do_action();
}
if (myvar) { do_action(); }
while (myvar) {
do_action();
}
while (myvar) { do_action(); }
BAD Examples:
if (myvar)
do_action();
if (myvar) do_action();
while (myvar)
do_action();
while (myvar) do_action();
2. ALWAYS Terminate JavaScript Statements with Semicolons
ALWAYS end every JavaScript statement with a semicolon (;).
Rationale: Semicolons make intent explicit, eliminate ASI surprises, improve readability, and produce clearer diffs and tooling output.
Scope: - Applies to all JavaScript statements — inside signal handlers (onClicked: { ... }), custom methods (function foo() { ... }), arrow function bodies, standalone .js files, and test files. - Does NOT apply to QML declarative property bindings (width: 100, text: "foo", anchors.centerIn: parent, model: myModel, etc.). These are not statements; adding ; after them is either a syntax error or non-idiomatic in QML. - When multiple QML bindings are written on a single line for compactness, ; is used only as a separator between bindings (Qt/QML convention), not as a statement terminator.
GOOD (JavaScript statements):
// Inside a QML signal handler or method
onClicked: {
root.toggleTailscale();
ToastService.showInfo("Toggled");
}
function buildCommand(hostname) {
if (hostname === "") {
return ["tailscale", "set", "--exit-node="];
}
return ["tailscale", "set", "--exit-node=" + hostname];
}
// In a .js file
if (!peerMap) {
return [];
}
return Object.keys(peerMap).map(...);
BAD (missing semicolons on statements):
if (condition) {
doAction()
}
return value
BAD (incorrect semicolon on QML binding — never do this):
width: 360; // OK (separator on same line)
height: 400; // WRONG — this is a binding, not a statement
text: "Tailscale"; // WRONG
GOOD (correct QML binding style):
width: 360
height: 400
text: "Tailscale"
Item { width: 1; height: 1; Layout.fillWidth: true } // ; only as separator