CLAUDE.md 7.3 KB

CLAUDE.md

Guidance for Claude Code (and human contributors) working in this repository.

What ArozOS is

ArozOS is a self-hosted, web-based cloud desktop / NAS operating system written in Go. It runs as a single binary on everything from a Raspberry Pi to a desktop server. The Go module lives in src/ (module path imuslab.com/arozos); the repository root holds docs, the installer and release tooling.

License: GPLv3 (see LICENSE).

Build, run and test

All Go commands run from src/:

cd src
go mod tidy
go build              # produces ./arozos
./arozos -port 8080   # run (sudo only needed for hardware/WiFi features)

go test ./...         # run the test suite
go vet ./...          # static checks
gofmt -l .            # list unformatted files (should be empty)
make binary           # cross-compile every supported OS/arch (see Makefile)

Mandatory contribution rules

These five rules are enforced on new and changed code by a Claude Code PostToolUse hook (during editing) and by CI (on every pull request). Both call scripts/check-conventions.sh. Existing legacy code is grandfathered — CI only inspects the lines a change adds — but do not add new violations, and prefer fixing nearby ones when you touch them.

1. Use the managed logger, never the standard log package

New code must send log output through the system logger so it lands in the managed, rotated system log instead of bare stdout.

import "imuslab.com/arozos/mod/info/logger"

// Good — title, message, and the originating error (nil if none):
logger.PrintAndLog("ModuleName", "could not open config", err)

// Bad — bypasses the system log:
log.Println("could not open config", err)   // and log.Printf/Fatal/Panic

The package-level logger.PrintAndLog delegates to the system-wide logger wired up in src/main.go; you do not need your own *logger.Logger instance. The only file allowed to wrap the standard log package is the logger implementation itself (src/mod/info/logger/).

Enforced as an ERROR (blocks CI) on added log.Print* / log.Fatal* / log.Panic* calls.

2. New functions ship with tests

Every package under src/mod/ is expected to carry a *_test.go file, and new functions must come with table-driven Go tests (see src/mod/info/logger/logger_test.go for the house style: t.TempDir(), t.Fatalf/t.Errorf, one Test… per behaviour).

cd src && go test ./mod/yourpackage/    # must pass before you push

Enforced by the CI go test ./... gate; the convention checker additionally warns when a touched mod/ package has no test file at all.

3. Dependencies must be MIT / commercial-use-OK

Any module added to src/go.mod must be licensed MIT, BSD-2/3, Apache-2.0, MPL-2.0, or ISC — permissive, GPL-compatible, and fine for commercial redistribution. Do not add GPL/AGPL/LGPL, source-available (BSL/SSPL), or unknown-licensed modules. When unsure, state the dependency's license in your summary so it can be reviewed before merge.

go install github.com/google/go-licenses@latest   # optional audit helper
go-licenses report imuslab.com/arozos

Enforced by a CI reminder whenever go.mod/go.sum changes — verify the license of each new dependency before merging.

4. New endpoints get the right security control

Register authenticated endpoints through the permission router, not raw http.HandleFunc, so they inherit login, per-module permission and (optionally) admin/LAN/CSRF checks:

import prout "imuslab.com/arozos/mod/prouter"

router := prout.NewModuleRouter(prout.RouterOption{
    ModuleName:    "System Setting",
    AdminOnly:     true,            // gate admin-only actions
    UserHandler:   userHandler,
    DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
        utils.SendErrorResponse(w, "Permission Denied")
    },
})
router.HandleFunc("/system/yourmodule/action", yourHandler)

Use raw http.HandleFunc only for deliberately public endpoints (e.g. the /public/... registration pages) and treat all request input as untrusted — validate parameters with mod/utils helpers and never interpolate user input into shell commands or file paths. See src/main.router.go and src/register.go for the patterns.

Enforced by a CI/hook warning on every added raw http.HandleFunc, prompting a deliberate "authenticated vs. intentionally public" decision.

5. Stay portable — no system dependencies, cross-platform safe

ArozOS ships as one self-contained binary that must build and run across the targets in the Makefile (Linux amd64/386/arm/arm64/mipsle/ riscv64, macOS, Windows). Therefore:

  • No hardcoded OS paths. Build paths with filepath.Join, and resolve locations via os.TempDir(), os.UserHomeDir(), or paths relative to the binary — never literal "/usr/...", "/etc/..." or "C:\\...".
  • No shelling out to platform tools in shared code. Avoid making features depend on external binaries. When a platform-specific call (exec.Command, syscall) is unavoidable, isolate it in a build-tagged file — foo_linux.go, foo_windows.go, foo_darwin.go, or behind a //go:build constraint — and provide a fallback for other platforms. See src/mod/network/wifi/ for the pattern.
  • Cross-compile to sanity-check: cd src && GOOS=windows GOARCH=amd64 go build ./....

Enforced as an ERROR on added hardcoded OS path literals, and as a warning when exec.Command/syscall appears in a non-build-tagged file.

How enforcement works

Mechanism When it runs What it does
PostToolUse hook (.claude/settings.json) After Claude edits a Go file Runs the checker on that file and feeds any finding back so Claude self-corrects
GitHub Actions (.github/workflows/ci.yml) On every push / PR gofmt, go build, go test ./..., and the diff-scoped convention checker (blocking); plus module-wide go vet (advisory — never fails CI on grandfathered legacy code)
scripts/check-conventions.sh Manually or from the above Single source of truth for the rules above

Run it yourself before pushing:

sh scripts/check-conventions.sh src/path/to/file.go     # check specific files
sh scripts/check-conventions.sh --diff origin/master     # check everything you changed

Escape hatch: in the rare, justified case where a line must keep a raw log/path literal, append the marker arozos-lint-ignore to that line with a short comment explaining why. Use it sparingly — it is reviewed.

Repository layout cheatsheet

  • src/ — Go module root; main*.go boot the server, *.go are feature handlers.
  • src/mod/ — self-contained library packages (each with its own tests).
  • src/mod/info/logger/ — the system logger (rule 1).
  • src/mod/prouter/ — permission/auth router (rule 4).
  • src/web/ — front-end assets and web apps.
  • src/system/ — runtime data and config (not shipped in release).