dms_tailscalectl/AGENTS.md

141 lines
No EOL
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 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 `master` or `testing without explicit human instruction.
- **NEVER** merge into `master` or `testing` without 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:**
1. It is the authoritative source of truth owned by this component.
2. It delivers actionable feedback that meaningfully improves the user experience or a decision.
3. It provides a demonstrable and reasonably argued security or performance improvement (the burden of proof is on the proposer).
4. 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**
1. Wrong solution to the actual problem. This project is a GUI wrapper around the `tailscale` binary. If the binary doesnt exist, there is nothing to do except surface an error. Storing a flag and guarding UI actions adds state for no gain.
2. 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.”
3. 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:
```javascript
if (myvar) {
do_action();
}
```
```javascript
if (myvar) { do_action(); }
```
```javascript
while (myvar) {
do_action();
}
```
```javascript
while (myvar) { do_action(); }
```
**BAD** Examples:
```javascript
if (myvar)
do_action();
```
```javascript
if (myvar) do_action();
```
```javascript
while (myvar)
do_action();
```
```javascript
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):
```javascript
// 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];
}
```
```javascript
// In a .js file
if (!peerMap) {
return [];
}
return Object.keys(peerMap).map(...);
```
BAD (missing semicolons on statements):
```javascript
if (condition) {
doAction()
}
return value
```
BAD (incorrect semicolon on QML binding — never do this):
```javascript
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):
```javascript
width: 360
height: 400
text: "Tailscale"
Item { width: 1; height: 1; Layout.fillWidth: true } // ; only as separator
```