Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Domain specification (rules, report structure) lives in `README.md`.

## Operating protocol (must follow)

This protocol assumes you are running inside the Claude Code VS Code extension, interacting with the user directly in chat. All communication (design briefs, questions, approvals) happens in the chat not via GitHub issue comments.
This protocol assumes you are running inside the Claude Code VS Code extension, interacting with the user directly in chat. All communication (design briefs, questions, approvals) happens in the chat - not via GitHub issue comments.

### Phase 1 - Clarify and design (no code)

Expand Down Expand Up @@ -67,7 +67,7 @@ After design approval:
2. Implement the full approved design.
3. Include tests (see "Testing approach" below). Tests are mandatory.
4. Run `go test ./...` and ensure all tests pass. If any test fails, fix the code or the test before proceeding.
5. Do not commit yet leave changes uncommitted so the user can review the diff in their IDE.
5. Do not commit yet - leave changes uncommitted so the user can review the diff in their IDE.

### Phase 3 - Review, commit, and open PR

Expand All @@ -88,7 +88,7 @@ After implementation is complete and tests pass:

When the user requests changes on the PR (either in chat or via GitHub review comments):
- Push follow-up commits to the same branch addressing each comment.
- Do not force-push or squash on the branch the user needs to see what changed since their review.
- Do not force-push or squash on the branch - the user needs to see what changed since their review.
- If a review comment requires a design change (not just a code tweak), explain the updated approach in chat before implementing it.
- After pushing fixes, run `go test ./...` again.

Expand Down Expand Up @@ -130,8 +130,9 @@ The scanner is an importable Go package (`package scanner`) at the module root.
## Go style preferences

### General
- Never use em dashes (-). Use simple hyphens (-) everywhere - in code, comments, docs, and reports.
- Concise, explicit code. No clever abstractions.
- Flat control flow early returns, avoid deep nesting.
- Flat control flow - early returns, avoid deep nesting.
- Errors are values. Wrap with context: `fmt.Errorf("scan repo %s: %w", name, err)`.
- No `panic` except in truly unrecoverable startup failures.
- Log with `log.Printf` / `log.Fatalf` (standard library). No structured logging libraries yet.
Expand All @@ -144,7 +145,7 @@ The scanner is an importable Go package (`package scanner`) at the module root.
### Naming
- Follow Go conventions: `MixedCase` for exported, `mixedCase` for unexported.
- Interfaces named by what they do: `RepoLister`, `FileChecker`, not `IClient` or `ClientInterface`.
- The main GitHub interface is `GitHubClient` (exception to the verb rule it's the central abstraction).
- The main GitHub interface is `GitHubClient` (exception to the verb rule - it's the central abstraction).

---

Expand Down Expand Up @@ -212,14 +213,14 @@ Report generation tests must verify the Markdown output matches expected structu

## Do-s
- Prefer concise, explicit code over clever abstractions.
- Validate required inputs up front in `main()` fail fast with actionable messages.
- Use `context.Context` for GitHub API calls respect cancellation and timeouts.
- Validate required inputs up front in `main()` - fail fast with actionable messages.
- Use `context.Context` for GitHub API calls - respect cancellation and timeouts.
- Keep the `GitHubClient` interface narrow. Only add methods when a rule actually needs them.
- Handle GitHub API rate limits gracefully log remaining quota, fail clearly when exhausted.
- Handle GitHub API rate limits gracefully - log remaining quota, fail clearly when exhausted.

## Don't-s
- Don't add abstractions until they're needed by real code (no speculative interfaces or generic helpers).
- Don't write huge functions if a function exceeds ~40 lines, it probably does too much.
- Don't write huge functions - if a function exceeds ~40 lines, it probably does too much.
- Don't log secrets (tokens, private repo contents).
- Don't ignore errors. Every `err` must be checked.
- Don't reach for external packages when the standard library suffices.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ No dashboard. No database. No setup beyond installing the GitHub App. Scan, repo

## Rules

Each rule produces a **pass** or **fail** result per repository. There are no scores, weights, or severity levels just pass/fail.
Each rule produces a **pass** or **fail** result per repository. There are no scores, weights, or severity levels - just pass/fail.

### Repo basics

Expand Down Expand Up @@ -93,14 +93,14 @@ Each rule produces a **pass** or **fail** result per repository. There are no sc

#### 10. Has required reviewers

**Check:** the default branch's branch protection rules require at least one approving review before merging (via the GitHub API `required_pull_request_reviews.required_approving_review_count >= 1`).
**Check:** the default branch's branch protection rules require at least one approving review before merging (via the GitHub API - `required_pull_request_reviews.required_approving_review_count >= 1`).

**Pass:** required reviewers is set to 1 or more.
**Fail:** required reviewers is not configured, or set to 0, or branch protection is not enabled.

#### 11. Requires status checks before merging

**Check:** the default branch's branch protection rules require at least one status check to pass before merging (via the GitHub API `required_status_checks` is configured with one or more contexts).
**Check:** the default branch's branch protection rules require at least one status check to pass before merging (via the GitHub API - `required_status_checks` is configured with one or more contexts).

**Pass:** at least one required status check is configured.
**Fail:** required status checks are not configured, or the list of required contexts is empty, or branch protection is not enabled.
Expand All @@ -112,7 +112,7 @@ Each rule produces a **pass** or **fail** result per repository. There are no sc
The report is a single Markdown document posted as a GitHub Issue. Structure:

```
# Codatus Org Compliance Report
# Codatus - Org Compliance Report

**Org:** {org_name}
**Scanned:** {timestamp}
Expand Down
2 changes: 1 addition & 1 deletion report.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
func GenerateReport(org string, results []RepoResult) string {
var b strings.Builder

b.WriteString("# Codatus Org Compliance Report\n\n")
b.WriteString("# Codatus - Org Compliance Report\n\n")
fmt.Fprintf(&b, "**Org:** %s\n", org)
fmt.Fprintf(&b, "**Scanned:** %s\n", time.Now().UTC().Format("2006-01-02 15:04 UTC"))
fmt.Fprintf(&b, "**Repos scanned:** %d\n", len(results))
Expand Down
2 changes: 1 addition & 1 deletion report_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func TestGenerateReport_Structure(t *testing.T) {
report := GenerateReport("test-org", results)

// Header
if !strings.Contains(report, "# Codatus Org Compliance Report") {
if !strings.Contains(report, "# Codatus - Org Compliance Report") {
t.Error("missing report title")
}
if !strings.Contains(report, "**Org:** test-org") {
Expand Down
2 changes: 1 addition & 1 deletion scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func Run(ctx context.Context, cfg Config) error {

report := GenerateReport(cfg.Org, results)

title := fmt.Sprintf("Codatus %s Compliance Report", cfg.Org)
title := fmt.Sprintf("Codatus - %s Compliance Report", cfg.Org)
if err := client.CreateIssue(ctx, cfg.Org, cfg.ReportRepo, title, report); err != nil {
return fmt.Errorf("post report to %s/%s: %w", cfg.Org, cfg.ReportRepo, err)
}
Expand Down
Loading