diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..4339a62 --- /dev/null +++ b/.mailmap @@ -0,0 +1,12 @@ +# Canonical author for this repo. Earlier commits carry placeholder or host-generated +# identities (a repo-local "Your Name" config, unset user.email on some hosts, aider +# suffixes); this maps them all to the real author for git log / shortlog / blame. +Vuong Hoang +Vuong Hoang +Vuong Hoang +Vuong Hoang +Vuong Hoang +Vuong Hoang +Vuong Hoang +Vuong Hoang +Vuong Hoang diff --git a/README.md b/README.md index 32ddf1b..7c96eb7 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ Personal dotfiles. Configs are organized by where they get linked: | Folder | Links into | Examples | | -------------- | ------------ | --------------------------------- | -| `home_root` | `~` | `.zshrc`, `.wezterm.lua`, `.nanorc` | -| `home_config` | `~/.config` | `nvim`, `zellij`, `ghostty`, `aerospace` | +| `home_root` | `~` | `.zshrc`, `.zshenv`, `.gitconfig`, `.claude/`, `.local/bin/` | +| `home_config` | `~/.config` | `nvim`, `zellij`, `ghostty`, `aerospace`, `zsh`, `git` | | `windows` | Windows-only | `windows-terminal/settings.json` | | `lk-installers`| n/a | helper scripts to install tooling | @@ -16,6 +16,7 @@ One-shot, host-aware: ```bash ./link-dotfiles # link only (installs stow if missing) ./link-dotfiles --apps # fresh box: install all CLI tools, then link +./link-dotfiles --check # report drift (detached copies, dangling links); changes nothing ``` It detects the host (macOS vs Linux), installs [`stow`](https://www.gnu.org/software/stow/) @@ -40,6 +41,31 @@ The zsh prompt and plugins (zinit, Powerlevel10k, autosuggestions, syntax-highlighting, completions, vi-mode, fzf-tab) **self-install** from `.zshrc` on first shell start, so they're not part of `install-apps`. +Secrets never live here. `.zshenv` sources `~/.config/secrets/env.sh` if it +exists; that file is per-machine and comes from the vault (`secret`), not git. + +## Claude Code (`home_root/.claude`) + +Tracked, and linked into `~/.claude`: `CLAUDE.md` (global instructions), +`CONTEXT.md`, `settings.json`, `keybindings.json`, `statusline-command.sh`, +`bin/ratecheck`, and the `australis-design` skill. The per-repo login helper is +`home_config/zsh/claude-config-dir.zsh` together with +`home_root/.local/bin/claude-config-dir-init`. + +Deliberately **not** tracked: +- `.credentials.json` and `settings.local.json`, which are ignored. +- `projects/`, the per-project auto-memory and transcripts. +- Tool-managed skills (`graphify`, `synced`). +- The galdrabok skill links, which galdrabok owns. + +**Edit the repo path, never the link with `sed -i`.** `sed -i` and other +write-temp-then-rename editors replace the link with a detached copy, and this +repo then silently goes stale. That happened to `CLAUDE.md` and +`statusline-command.sh` in September 2026. Claude Code's Edit tool refuses to +write through a link and names the target, which is the safe behaviour. Claude +Code may also rewrite `settings.json` itself when settings change from inside the +app. After that, or whenever in doubt, run `./link-dotfiles --check`. + ## Windows (PowerShell) `stow` doesn't run natively on Windows, so use the PowerShell equivalent. It diff --git a/home_config/git/ignore b/home_config/git/ignore new file mode 100644 index 0000000..66d62f8 --- /dev/null +++ b/home_config/git/ignore @@ -0,0 +1 @@ +**/.claude/settings.local.json diff --git a/home_config/zsh/claude-config-dir.zsh b/home_config/zsh/claude-config-dir.zsh new file mode 100644 index 0000000..bc21c59 --- /dev/null +++ b/home_config/zsh/claude-config-dir.zsh @@ -0,0 +1,30 @@ +# Per-repo Claude Code login: a `.claude-config-dir` marker at (or above) the +# cwd names a config dir; while inside that tree CLAUDE_CONFIG_DIR points at +# $HOME/.claude- (or an absolute path if the marker holds one), so +# `claude` and `dev-launch claude` both pick up that login. Leaving the tree +# restores whatever was set before. Sourced from ~/.zshrc. +_claude_config_dir_apply() { + local dir="$PWD" marker="" name="" + while [[ "$dir" != "/" && -n "$dir" ]]; do + if [[ -f "$dir/.claude-config-dir" ]]; then marker="$dir/.claude-config-dir"; break; fi + dir="${dir:h}" + done + if [[ -z "$marker" ]]; then + if [[ -n "${_CLAUDE_CONFIG_DIR_BY_HOOK:-}" ]]; then + if [[ -n "${_CLAUDE_CONFIG_DIR_PREV:-}" ]]; then export CLAUDE_CONFIG_DIR="$_CLAUDE_CONFIG_DIR_PREV"; else unset CLAUDE_CONFIG_DIR; fi + unset _CLAUDE_CONFIG_DIR_BY_HOOK _CLAUDE_CONFIG_DIR_PREV + fi + return + fi + name="$(<"$marker")"; name="${name//[[:space:]]/}" + [[ -z "$name" ]] && return + local target + if [[ "$name" == /* ]]; then target="$name"; else target="$HOME/.claude-$name"; fi + if [[ -z "${_CLAUDE_CONFIG_DIR_BY_HOOK:-}" ]]; then _CLAUDE_CONFIG_DIR_PREV="${CLAUDE_CONFIG_DIR:-}"; fi + _CLAUDE_CONFIG_DIR_BY_HOOK=1 + export CLAUDE_CONFIG_DIR="$target" + [[ -d "$target" ]] || print -u2 "claude-config-dir: $target does not exist yet — run: claude-config-dir-init $target" +} +autoload -Uz add-zsh-hook +add-zsh-hook chpwd _claude_config_dir_apply +_claude_config_dir_apply diff --git a/home_root/.claude/CLAUDE.md b/home_root/.claude/CLAUDE.md index 79e7112..8d009b0 100644 --- a/home_root/.claude/CLAUDE.md +++ b/home_root/.claude/CLAUDE.md @@ -12,8 +12,11 @@ use `sed -i` or any other write-temp-then-rename tool on `~/.claude/CLAUDE.md`:** that replaces the link with a detached copy, and the dotfiles backup silently goes stale. It happened once already, around 2026-09-18, and went unnoticed until 2026-09-24. The same -applies to `statusline-command.sh`, `CONTEXT.md` and -`keybindings.json` in `~/.claude`. +applies to every other linked file: in `~/.claude` that is +`settings.json`, `statusline-command.sh`, `CONTEXT.md`, +`keybindings.json`, `bin/ratecheck` and `skills/australis-design`, plus +`~/.zshrc`, `~/.zshenv` and `~/.gitconfig`. `~/dotfiles/link-dotfiles +--check` reports any file that has come loose, and any dangling link. ## Operator identity diff --git a/home_root/.claude/bin/ratecheck b/home_root/.claude/bin/ratecheck new file mode 100755 index 0000000..8fb41ad --- /dev/null +++ b/home_root/.claude/bin/ratecheck @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +"""Read the rate-limit window and say whether a consult may be dispatched. + +The percentages exist only in the JSON the harness pipes to the statusline; no CLI +subcommand exposes them and nothing else on disk carries them. `~/.claude/statusline-command.sh` +tees them to ~/.claude/rate-limits.json on every render (added 2026-09-05, operator directive); +this reads that file. + +Exit codes: 0 GO 1 PAUSE 2 UNKNOWN + +⚠ UNKNOWN is NOT a pause. A stale or missing file means the instrument is broken, and a +broken instrument that halts every consult is a self-inflicted outage worse than the +overspend it guards. UNKNOWN proceeds and says so loudly, so the gap is visible rather +than silently protective. +""" +import json, os, sys, time + +THRESHOLD = 93.0 # advisory default; a project may set its own and say so +STALE_SECONDS = 900 # the statusline renders constantly in an interactive session + +PATH = os.path.join(os.environ.get("CLAUDE_CONFIG_DIR") or os.path.expanduser("~/.claude"), "rate-limits.json") + + +def main() -> int: + try: + with open(PATH, encoding="utf-8") as fh: + d = json.load(fh) + except FileNotFoundError: + print(f"UNKNOWN no {PATH} — statusline tee missing or never rendered") + return 2 + except (OSError, ValueError) as exc: + print(f"UNKNOWN {PATH} unreadable: {exc}") + return 2 + + five, seven = d.get("five_hour_pct"), d.get("seven_day_pct") + age = time.time() - (d.get("written_at") or 0) + stamp = d.get("written_at_iso", "?") + + if five is None and seven is None: + print(f"UNKNOWN both windows null (written {stamp}) — session reported no rate_limits") + return 2 + if age > STALE_SECONDS: + print(f"UNKNOWN stale by {age/60:.0f} min (written {stamp}) — " + f"last seen 5h={five} 7d={seven}; the statusline is not rendering") + return 2 + + worst = max(v for v in (five, seven) if v is not None) + which = "5h" if five == worst else "7d" + line = (f"5h={five if five is not None else '?'}% " + f"7d={seven if seven is not None else '?'}% " + f"(age {age/60:.1f} min, threshold {THRESHOLD}%)") + + if worst >= THRESHOLD: + reset = d.get(f"{'five_hour' if which == '5h' else 'seven_day'}_resets_at") + when = (time.strftime("%H:%MZ", time.gmtime(reset)) if reset else "unknown") + print(f"PAUSE {line} — {which} at {worst}% >= {THRESHOLD}%; resets {when}") + return 1 + + print(f"GO {line}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/home_root/.claude/settings.json b/home_root/.claude/settings.json new file mode 100644 index 0000000..4b8dbac --- /dev/null +++ b/home_root/.claude/settings.json @@ -0,0 +1,109 @@ +{ + "env": { + "VOR_URL": "http://10.250.50.70:7879", + "DISABLE_AUTOUPDATER": "1" + }, + "attribution": { + "commit": "", + "pr": "", + "sessionUrl": false + }, + "includeCoAuthoredBy": false, + "permissions": { + "defaultMode": "auto" + }, + "model": "opus[1m]", + "hooks": { + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "test -f .corviduo-canonicals.toml && python scripts/canonical_drift.py 2>&1 || true" + } + ] + } + ], + "UserPromptSubmit": [ + { + "hooks": [ + { + "type": "command", + "command": "printf '%s' '{\"hookSpecificOutput\": {\"hookEventName\": \"UserPromptSubmit\", \"additionalContext\": \"SVOS markers, one line each, first person. FIRST line of the reply: ⟦INTENT⟧ (append — for when a peer or althing message drove it). FINAL lines, always all three, in order: ⟦STATE⟧ ; ⟦AWAITING⟧ ; ⟦DECIDE⟧ . When ⟦AWAITING⟧ or ⟦DECIDE⟧ has nothing, its entire payload is the two words Nothing pending — no period, no dash, no words after. If autonomous turns ran since the operator last spoke, add a Since your last turn digest directly after ⟦INTENT⟧: one line per turn, what changed, what it cost, every irreversible or outward-facing effect named.\"}}'" + } + ] + } + ] + }, + "statusLine": { + "type": "command", + "command": "bash \"$HOME/.claude/statusline-command.sh\"" + }, + "enabledPlugins": { + "frontend-design@claude-plugins-official": true, + "althing@althing": true, + "pyright-lsp@claude-plugins-official": true, + "rust-analyzer-lsp@claude-plugins-official": true + }, + "extraKnownMarketplaces": { + "althing": { + "source": { + "source": "directory", + "path": "/home/lkraven/.local/share/althing-plugin" + } + } + }, + "feedbackDrafts": "off", + "effortLevel": "xhigh", + "modelSettings": { + "claude-fable-5-1": { + "effortLevel": "high" + }, + "claude-opus-5-5": { + "effortLevel": "xhigh" + } + }, + "tui": "default", + "skipDangerousModePermissionPrompt": true, + "skipWorkflowUsageWarning": true, + "theme": "dark", + "preferredNotifChannel": "terminal_bell", + "remoteControlAtStartup": false, + "crossSessionInbound": "accept", + "agentPushNotifEnabled": true, + "skipAutoPermissionPrompt": true, + "autoMode": { + "allow": [ + "$defaults", + "Bash(uv:*) — declared/standard toolchain command, 219 occurrences in this project, already dependency-adjacent", + "Bash(postbox:*) in this project — althing messaging client, 28 occurrences, routine multi-agent coordination" + ], + "environment": [ + "### Org-wide", + "**Organization**: Corviduo AI / PhaseFinal, Inc / VastBlue AI — three organizations under operator Vuong Hoang (lkraven); this repo (hamr) is a PhaseFinal-hosted gitea project", + "**Cloud provider(s)**: None configured", + "**Repository visibility**: assume private unless the remote host and repo name indicate otherwise, or a visibility check in the transcript shows public — gh visibility check not queryable (org/repo not derivable from origin remote); gitea.phasefinal.com is a private self-hosted org host, no public-visibility evidence found", + "**Internal sharing / snippet hosting**: The Booth (http://10.100.10.50:8090/) for ephemeral media/results; no auth, LAN/WG-internal only — do not drop secrets there", + "**Secrets management**: Vaultwarden-backed `secret` CLI on nh3-dev (vaultwarden.phasefinal.com) — vault is credential source of truth", + "**Default / protected branches**: not queryable via gh (org/repo not derivable from origin remote) — origin/HEAD unset locally too; treat default branch as unknown, do not assume unprotected", + "**CI/CD deploy targets**: None configured", + "**Network posture**: None configured", + "**Host containment**: None configured — assume ordinary developer machine (nh3-dev) with open internet per CLAUDE.md tooling notes", + "**Source control**: gitea.phasefinal.com:vh/hamr.git (this repo's origin) — no additional orgs configured", + "**Trusted internal domains**: gitea.phasefinal.com (org git host, seen in remotes and contacted hosts)", + "**Trusted cloud buckets**: None configured", + "**Key internal services**: 10.100.50.40 (althing post office, 90x contacted), 10.100.10.50 (nh3-dev / Booth / Playwright host, 19x contacted), 10.100.79.3 (7x contacted, unlabeled)", + "**Internal package registry**: None configured", + "**Sensitive data locations & audiences**: any file or store holding personal data, confidential business data, credentials, regulated data, or similarly sensitive material; preserve exact handles when known and share only with audiences cleared at the [named+specifics] bar; note a redacted unusual .gitignore pattern plus `.env` suggest local secrets/config in this repo not meant for commit", + "**Data retention / declassification**: None configured", + "**Sensitive remote targets**: any namespace, host, or container whose name carries `prod` or `production` as a whole word or name segment", + "**Protected deployment namespaces / environments**: None configured — fall back to the Sensitive remote targets heuristic; k8s namespaces seen in this project's transcripts (`hamr`, `docs`) show no prod marker", + "**Protected IaC scopes**: IAM, RBAC, networking, quota, and node-pool resources; anything whose name or tag carries `prod` or `production` as a whole word or name segment", + "### User-specific", + "**Primary use of Claude Code**: software development — geometric-truth vectorization library (hamr), contract-first TDD workflow", + "**Trusted repo**: /home/lkraven/development/hamr (gitea.phasefinal.com:vh/hamr.git) — this repo and its origin remote only", + "**Org-specific CLIs**: uv (Python, primary), postbox / althing-listen (althing messaging bus), booth (media board helper), park, graphify, secret (Vaultwarden CLI, referenced in global CLAUDE.md but not observed in this project's transcripts)", + "**Routine under vh/ prefix**: gitea.phasefinal.com:vh/* repos (own org namespace) are the operator's own checkouts per global CLAUDE.md, but only this project's repo (hamr) is in scope per the just-this-project setting" + ] + } +} diff --git a/home_root/.claude/skills/australis-design/README.md b/home_root/.claude/skills/australis-design/README.md new file mode 100644 index 0000000..505ef71 --- /dev/null +++ b/home_root/.claude/skills/australis-design/README.md @@ -0,0 +1,162 @@ +# Australis Design System + +> Cool, calm, terminal-first. A dark color and UI system inspired by the Aurora Australis — the Southern Lights. + +Australis is a **comfort-focused dark theme** for technology products. The color core was already defined (16 ANSI-style terminal colors, all cooler than neutral, medium-contrast, perceived LAB lightness 65 base / 80 bright). This system extends that core into a full visual language: typography, spacing, elevation, motion, and component patterns suited to terminals, code editors, dashboards, and developer tooling. + +The original color spec lives in `uploads/README.md` — © 2024 Vuong Hoang. + +--- + +## Index + +- **`README.md`** — this file (visual + content foundations, iconography) +- **`colors_and_type.css`** — design tokens (CSS custom properties + base element styles). Import this from any HTML. +- **`SKILL.md`** — front-matter for using this as a downloadable Claude Skill +- **`assets/`** — logo (mark + wordmark) — see _Caveats_ below +- **`preview/`** — design-system preview cards (registered for the Design System tab) +- **`ui_kits/terminal/`** — interactive terminal + code-editor surface (the signature use-case) + - `index.html`, `Terminal.jsx`, `Editor.jsx`, `StatusBar.jsx`, `Sidebar.jsx`, `CommandPalette.jsx` + +## Sources we were given + +- **`uploads/README.md`** — the Australis Dark color theme spec (full palette + rationale) +- _No codebase, Figma, or product screens were supplied._ The "technology stack" framing in the brief is interpreted as **developer tooling** (terminal, editor, CLI dashboard) — that's the surface this system is built for. If a real product exists, send it over and we'll re-skin the UI kit accordingly. + +--- + +## Content Fundamentals + +Australis copy reads like good terminal output: **direct, lowercase-leaning, low ceremony**. Information dense, never chatty. + +- **Tone** — calm, technical, slightly understated. Confident without exclamation marks. Think `man` page meets a well-lit cabin. +- **Voice** — second-person (`you`) for instructional copy. First-person plural (`we`) only when the system is doing something on behalf of the user (`we'll never share it`). Avoid "I" — there's no persona. +- **Casing** — sentence case for everything: buttons, headings, menu items. The wordmark itself is lowercase: `australis`. Eyebrows and metadata may be UPPERCASE (mono, wide-tracked) — that's the only place caps appear. +- **Punctuation** — periods optional on UI strings of one short sentence. Use em-dashes for asides. Code identifiers, hex codes, and paths go in `monospace`. +- **Numbers + units** — keep tight: `184ms`, `12kb`, `v1.2.0`. Spell out only when prose-natural ("twelve modules"). +- **No emoji.** No exclamation marks. No marketing superlatives. Status uses glyphs (`✓ ✗ !`) or icons, not emoji. +- **Vibe** — engineer-grade clarity. The product respects the user's attention. + +**Examples** + +> ✓ tokens compiled (184ms) +> ! 2 deprecated tokens — see migration.md +> ✗ assets/logo.svg not found + +> Use 8+ characters with mixed case. + +> Aurora prod · staging · preview + +> Deploy · Cancel · Learn more + +--- + +## Visual Foundations + +### Palette philosophy + +- Three families: **Ice** (surface neutrals, cool-tinted), **Aurora** (primary blue/cyan/green — use generously, in that preference order), **Dawn** (red/yellow/magenta accents — use sparingly). +- Neutral scale shifts from cool blue toward green as it brightens. This is the signature — don't flatten it. +- Black = `#222531`, never pure `#000`. White = `#a9bcc3`, never pure `#fff`. The eye sits in low-contrast cool grey; emphasis is achieved by *brightness*, not saturation. +- Semantic mapping: info → blue, success → green, warning → yellow, danger → red. Magenta is reserved for keywords / brand moments. + +### Backgrounds + +- **Always dark first.** No light mode in this system. +- Solid fills only on chrome — no full-bleed photography, no decorative gradients. +- One sanctioned gradient: the **aurora glow**, a vertical `bright-blue → bright-cyan → green` (see `--glow-*` tokens, the logo, and accent edges). Used at low opacity, never as a background fill behind text. +- No textures, no noise, no patterns. The screen is the polar sky — empty, with light *coming through* it. + +### Type + +- **Display** — Space Grotesk (geometric humanist; -0.015em tracking). +- **UI / Body** — Inter (15px default body, 1.5–1.65 line-height). +- **Mono** — JetBrains Mono (terminal, code, eyebrows, metadata, hex codes). +- Eyebrows and metadata are **mono uppercase, 11px, 0.08em tracked** — this is one of the system's signatures. Use them often. +- Min sizes: 11px on UI metadata; 13px on body in compact density; 15px default. Never below 11px. + +### Spacing & layout + +- 4px base. Use the `--sp-*` scale; don't invent in-between values. +- Information density is **medium-high**, especially in chrome (toolbars, sidebars). Marketing surfaces breathe more. +- Containers: `sm 640 / md 880 / lg 1200 / xl 1440`. Center on canvas; no full-bleed marketing layouts. + +### Borders + +- Default border `--border-default` (`#565f69`) at 1px. Subtle dividers use `--border-subtle` (`#414751`). +- **Border > shadow** for grouping in chrome. Cards layer one subtle shadow on top of a 1px border. +- Featured cards use a 2px **top edge** in `--aus-blue` instead of changing the fill — this is the only sanctioned "accent border" pattern. Never colored *left* borders (the LLM-slop trope). + +### Corners + +- `--radius-sm` (4px) for inputs, badges, small chrome. +- `--radius-md` (6px) for buttons, tags. +- `--radius-lg` (10px) for cards, panels. +- `--radius-pill` only for status badges and toggle switches. +- Terminal/editor surfaces stay at `--radius-md` or `--radius-lg`. The inner code area itself is square. + +### Shadows / elevation + +- Shadows are tinted with `rgba(10, 12, 18, *)` — cooler than pure black, matching the bg. +- 4 elevation steps. Most chrome lives at `shadow-1` or `shadow-2`. Modals at `shadow-3`. Heavy popovers at `shadow-4`. +- **Aurora glow** (`--glow-blue/cyan/green`): used as a 3px focus ring or a hover lift on primary buttons. This is the system's signature interaction motif. +- **Inset shadow** (`--shadow-inset`) for terminal wells and sunken inputs — subtle highlight on top edge + dark inner border. + +### States + +- **Hover** — shift one step *brighter* on neutrals (e.g. `bright-black → dark-30`). Primary buttons: `blue → bright-blue`. Never lower opacity to indicate hover. +- **Active / pressed** — slight downward shift (`translateY(1px)`) + a step *darker* on neutrals, or a desaturated primary. +- **Focus-visible** — 3px aurora glow ring (`--glow-blue` by default; `--glow-green` for success controls). +- **Disabled** — `opacity` is fine here; combine with `cursor: not-allowed`. + +### Motion + +- Calm, never bouncy. No springs, no overshoot. +- `--ease-out` for entries, `--ease-in-out` for state changes, `--ease-aurora` for hero/long transitions. +- Durations: `120ms` for hovers, `200ms` for state, `320ms` for panels, `800ms` for hero. +- Aurora glow may breathe on the brand mark (8s slow opacity oscillation) — this is the only continuous animation sanctioned by default. + +### Transparency & blur + +- Glass surfaces (modals, popovers over content) use `--bg-glass` (`rgba(55,59,70,0.55)`) with `backdrop-filter: blur(16px)`. Cap at 16px blur — anything more turns muddy on cool palettes. +- Scrims use `--bg-overlay` (`rgba(34,37,49,0.72)`) — solid feel, no blur. +- Otherwise, opacity is for disabled states only. + +### Imagery + +- Black-and-white or cool-tinted photography. No warm-tinted hero imagery — it fights the system. +- Reserved use; this is a chrome-first system, not an editorial one. + +### Layout fixtures + +- Top chrome: 44–52px tall (status bar / tab bar). +- Sidebar: 240–280px (collapsible to 56px icon rail). +- Status bar: 24–28px (mono, 11px). +- Hit targets: 32px min in dense chrome, 40px+ in marketing/settings. + +--- + +## Iconography + +Australis uses **[Lucide](https://lucide.dev)** — a clean, line-first icon set that matches the system's pen-stroke restraint. + +- **Stroke weight** — `1.75` (slightly heavier than Lucide default for legibility on dark). +- **Default size** — `22px` in chrome, `16px` in dense lists. +- **Color** — `currentColor`. Always inherit from the surrounding text (use `--fg-1` or `--fg-2`). +- **Style** — line, never filled. Two-tone is forbidden. +- **No emoji** anywhere in the UI. Status uses Lucide icons (`check-circle`, `x-circle`, `alert-triangle`, `info`) or mono glyphs (`✓ ✗ ! ➜`). +- **Unicode glyphs** — sanctioned for terminal/CLI surfaces only: `➜ ✓ ✗ ! ⚡ ●`. They feel native there. Outside the terminal, use Lucide. + +### Where to get them + +The CDN is the simplest path: `` and `lucide.createIcons()`. For static HTML cards (preview surfaces), inline the SVG with `stroke-width="1.75" stroke="currentColor" fill="none"`. The `preview/brand-icons.html` card shows 16 hand-inlined examples in the right shape. + +If you need a glyph Lucide doesn't have, draw it with the same constraints: 24×24 viewBox, 1.75 stroke, rounded caps + joins, no fill. + +--- + +## Caveats + +- **Logo** — no real logo was provided. The `assets/logo-mark.svg` and `assets/logo-wordmark.svg` are interpretive placeholders (an aurora curtain over a horizon) sized to the system. **Replace with the real mark** when available, or tell us the brand voice and we'll commission one. +- **Type stack** — Space Grotesk / Inter / JetBrains Mono is **canonical**. Loaded from Google Fonts at the top of `colors_and_type.css`; exposed via `--font-display`, `--font-sans`, `--font-mono`; documented in _Visual Foundations → Type_. +- **Product surface** — no codebase or screens were attached. The UI kit (`ui_kits/terminal/`) reflects the *kind* of product Australis is built for (a developer tool); it's not a recreation of an existing product. diff --git a/home_root/.claude/skills/australis-design/SKILL.md b/home_root/.claude/skills/australis-design/SKILL.md new file mode 100644 index 0000000..4054de6 --- /dev/null +++ b/home_root/.claude/skills/australis-design/SKILL.md @@ -0,0 +1,13 @@ +--- +name: australis-design +description: Use this skill to generate well-branded interfaces and assets for Australis, either for production or throwaway prototypes/mocks/etc. Contains essential design guidelines, colors, type, fonts, assets, and UI kit components for prototyping. +user-invocable: true +--- + +Read the README.md file within this skill, and explore the other available files (especially `colors_and_type.css` for design tokens, `assets/` for the logo, `ui_kits/terminal/` for component recipes, and `preview/` for visual references). + +If creating visual artifacts (slides, mocks, throwaway prototypes, etc), copy assets out and create static HTML files for the user to view. Always import `colors_and_type.css` rather than reinventing tokens. + +If working on production code, you can copy assets and read the rules here to become an expert in designing with this brand. + +If the user invokes this skill without any other guidance, ask them what they want to build or design, ask some questions, and act as an expert designer who outputs HTML artifacts _or_ production code, depending on the need. diff --git a/home_root/.claude/skills/australis-design/assets/logo-mark.svg b/home_root/.claude/skills/australis-design/assets/logo-mark.svg new file mode 100644 index 0000000..4e072dd --- /dev/null +++ b/home_root/.claude/skills/australis-design/assets/logo-mark.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/home_root/.claude/skills/australis-design/assets/logo-wordmark.svg b/home_root/.claude/skills/australis-design/assets/logo-wordmark.svg new file mode 100644 index 0000000..f83db33 --- /dev/null +++ b/home_root/.claude/skills/australis-design/assets/logo-wordmark.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + australis + \ No newline at end of file diff --git a/home_root/.claude/skills/australis-design/colors_and_type.css b/home_root/.claude/skills/australis-design/colors_and_type.css new file mode 100644 index 0000000..22f587c --- /dev/null +++ b/home_root/.claude/skills/australis-design/colors_and_type.css @@ -0,0 +1,348 @@ +/* ========================================================================== + Australis Design System — Tokens + Color theme inspired by the Aurora Australis (Southern Lights). + Cool-tinted, medium-contrast, dark-first. + ========================================================================== */ + +/* -------- Webfonts (Google Fonts fallback — see README "Type") ------------ */ +@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Inter:wght@400;500;600;700&family=Space+Grotesk:wght@400;500;600;700&display=swap'); + +:root { + /* ==================================================================== + COLOR — RAW PALETTE (from Australis Dark spec) + All colors cooler than neutral. ANSI base = LAB 65, bright = LAB 80. + ==================================================================== */ + + /* Ice — Main / Surface */ + --aus-black: #222531; /* background — LAB 15, slightly cool */ + --aus-white: #a9bcc3; /* foreground — LAB 75 */ + --aus-bright-white: #cce7ec; /* highlight — LAB 90 */ + + /* Sea — Neutral darks (low-contrast surfaces, dividers, comments) */ + --aus-bright-black: #373b46; /* LAB 25 */ + --aus-dark-30: #414751; /* LAB 30 */ + --aus-dark-40: #565f69; /* LAB 40 */ + --aus-dark-50: #6e7882; /* LAB 50 */ + --aus-dark-60: #86929d; /* LAB 60 */ + + /* Sea — Neutral brights (hi-contrast text, emphasis) */ + --aus-bright-70: #9daeb6; /* LAB 70 */ + --aus-bright-80: #b3cbcf; /* LAB 80 */ + + /* Aurora — Primary (use generously; preference order: blue → cyan → green) */ + --aus-blue: #6388d8; + --aus-bright-blue: #a4c4ff; + --aus-cyan: #00b1a8; + --aus-bright-cyan: #42dcd1; + --aus-green: #16b866; + --aus-bright-green: #51e08a; + + /* Dawn — Accents (use sparingly) */ + --aus-red: #ff491a; + --aus-bright-red: #ff854f; + --aus-yellow: #e1c631; + --aus-bright-yellow: #ffe14e; + --aus-magenta: #9d78ff; + --aus-bright-magenta: #d8adff; + + /* ==================================================================== + SEMANTIC — SURFACE / FOREGROUND + ==================================================================== */ + + --bg-0: var(--aus-black); /* page / canvas */ + --bg-1: var(--aus-bright-black); /* card / panel */ + --bg-2: var(--aus-dark-30); /* hover / nested */ + --bg-3: var(--aus-dark-40); /* active / selected */ + --bg-overlay: rgba(34, 37, 49, 0.72); /* scrim, modal backdrop */ + --bg-glass: rgba(55, 59, 70, 0.55); /* blurred glass surface */ + + --border-subtle: var(--aus-dark-30); + --border-default: var(--aus-dark-40); + --border-strong: var(--aus-dark-50); + --border-focus: var(--aus-blue); + + --fg-0: var(--aus-bright-white); /* primary heading / emphasis */ + --fg-1: var(--aus-white); /* body text default */ + --fg-2: var(--aus-bright-70); /* secondary text */ + --fg-3: var(--aus-dark-60); /* tertiary / metadata */ + --fg-muted: var(--aus-dark-50); /* disabled / placeholder */ + --fg-comment: var(--aus-dark-50); /* code comments, low-emphasis */ + + /* On-color foregrounds — use against accent fills */ + --fg-on-blue: var(--aus-black); + --fg-on-cyan: var(--aus-black); + --fg-on-green: var(--aus-black); + --fg-on-yellow: var(--aus-black); + --fg-on-red: var(--aus-black); + --fg-on-magenta: var(--aus-black); + + /* ==================================================================== + SEMANTIC — STATUS / FEEDBACK + ==================================================================== */ + --status-info: var(--aus-blue); + --status-info-bg: rgba(99, 136, 216, 0.12); + --status-success: var(--aus-green); + --status-success-bg: rgba(22, 184, 102, 0.14); + --status-warning: var(--aus-yellow); + --status-warning-bg: rgba(225, 198, 49, 0.14); + --status-danger: var(--aus-red); + --status-danger-bg: rgba(255, 73, 26, 0.14); + + /* Syntax highlighting (canonical mapping) */ + --syn-keyword: var(--aus-magenta); /* keywords, control flow */ + --syn-function: var(--aus-blue); /* function names, types */ + --syn-string: var(--aus-green); + --syn-number: var(--aus-bright-cyan); + --syn-constant: var(--aus-yellow); + --syn-tag: var(--aus-cyan); + --syn-comment: var(--aus-dark-50); + --syn-error: var(--aus-red); + --syn-variable: var(--aus-white); + --syn-operator: var(--aus-bright-70); + + /* ==================================================================== + TYPE — FAMILIES + Display: Space Grotesk (geometric, slightly humanist — matches the + polar-aurora feel without being sterile). + UI/Body: Inter (workhorse, optimized for screens). + Mono: JetBrains Mono (developer-focused, hinted for terminals). + ==================================================================== */ + --font-display: "Space Grotesk", "Inter", ui-sans-serif, system-ui, sans-serif; + --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; + --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace; + + /* ==================================================================== + TYPE — SCALE (8px-grid friendly, slightly tightened) + ==================================================================== */ + --fs-3xs: 11px; + --fs-2xs: 12px; + --fs-xs: 13px; + --fs-sm: 14px; + --fs-md: 15px; /* body default */ + --fs-lg: 17px; + --fs-xl: 20px; + --fs-2xl: 24px; + --fs-3xl: 30px; + --fs-4xl: 38px; + --fs-5xl: 48px; + --fs-6xl: 64px; + + --lh-tight: 1.15; + --lh-snug: 1.3; + --lh-normal: 1.5; + --lh-relaxed: 1.65; + + --fw-regular: 400; + --fw-medium: 500; + --fw-semibold: 600; + --fw-bold: 700; + + --tracking-tight: -0.015em; + --tracking-normal: 0; + --tracking-wide: 0.04em; + --tracking-caps: 0.08em; /* uppercase eyebrows */ + + /* ==================================================================== + SPACING — 4px base + ==================================================================== */ + --sp-0: 0px; + --sp-1: 4px; + --sp-2: 8px; + --sp-3: 12px; + --sp-4: 16px; + --sp-5: 20px; + --sp-6: 24px; + --sp-7: 32px; + --sp-8: 40px; + --sp-9: 48px; + --sp-10: 64px; + --sp-11: 80px; + --sp-12: 96px; + + /* ==================================================================== + RADIUS + Modest rounding. Terminal/CLI surfaces stay sharp; UI surfaces breathe. + ==================================================================== */ + --radius-none: 0px; + --radius-xs: 2px; + --radius-sm: 4px; + --radius-md: 6px; + --radius-lg: 10px; + --radius-xl: 14px; + --radius-pill: 9999px; + + /* ==================================================================== + SHADOW / ELEVATION + Cool-tinted shadows (use the --aus-black hue, not pure black). + ==================================================================== */ + --shadow-1: 0 1px 2px rgba(10, 12, 18, 0.4); + --shadow-2: 0 2px 6px rgba(10, 12, 18, 0.45), 0 1px 2px rgba(10, 12, 18, 0.4); + --shadow-3: 0 8px 24px rgba(10, 12, 18, 0.5), 0 2px 6px rgba(10, 12, 18, 0.4); + --shadow-4: 0 24px 64px rgba(10, 12, 18, 0.6), 0 8px 16px rgba(10, 12, 18, 0.45); + + /* Inner shadow for inset wells (terminal-like) */ + --shadow-inset: inset 0 1px 0 rgba(204, 231, 236, 0.04), inset 0 0 0 1px rgba(0,0,0,0.2); + + /* Aurora glow — for focus rings and signature accents */ + --glow-blue: 0 0 0 3px rgba(99, 136, 216, 0.35); + --glow-cyan: 0 0 0 3px rgba(0, 177, 168, 0.35); + --glow-green: 0 0 0 3px rgba(22, 184, 102, 0.30); + + /* ==================================================================== + MOTION + Calm, never bouncy. Aurora moves slowly. + ==================================================================== */ + --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1); + --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); + --ease-aurora: cubic-bezier(0.65, 0, 0.35, 1); /* signature slow-glide */ + + --dur-fast: 120ms; + --dur-base: 200ms; + --dur-slow: 320ms; + --dur-aurora: 800ms; /* hero transitions */ + + /* ==================================================================== + LAYOUT + ==================================================================== */ + --container-sm: 640px; + --container-md: 880px; + --container-lg: 1200px; + --container-xl: 1440px; +} + +/* ========================================================================== + SEMANTIC ELEMENTS — apply tokens to bare HTML + Import this stylesheet and you get sensible defaults out of the box. + ========================================================================== */ + +html, body { + background: var(--bg-0); + color: var(--fg-1); + font-family: var(--font-sans); + font-size: var(--fs-md); + line-height: var(--lh-normal); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-rendering: optimizeLegibility; +} + +h1, h2, h3, h4, h5, h6 { + font-family: var(--font-display); + color: var(--fg-0); + font-weight: var(--fw-semibold); + letter-spacing: var(--tracking-tight); + line-height: var(--lh-tight); + margin: 0; +} + +h1 { font-size: var(--fs-5xl); } +h2 { font-size: var(--fs-4xl); } +h3 { font-size: var(--fs-2xl); font-weight: var(--fw-medium); } +h4 { font-size: var(--fs-xl); font-weight: var(--fw-medium); } +h5 { font-size: var(--fs-lg); font-weight: var(--fw-medium); } +h6 { + font-size: var(--fs-2xs); + font-weight: var(--fw-semibold); + text-transform: uppercase; + letter-spacing: var(--tracking-caps); + color: var(--fg-2); + font-family: var(--font-sans); +} + +p { + font-size: var(--fs-md); + line-height: var(--lh-relaxed); + color: var(--fg-1); + margin: 0 0 var(--sp-4); + text-wrap: pretty; + max-width: 68ch; +} + +small, .text-meta { + font-size: var(--fs-2xs); + color: var(--fg-3); + letter-spacing: var(--tracking-wide); +} + +a { + color: var(--aus-bright-blue); + text-decoration: none; + border-bottom: 1px solid transparent; + transition: color var(--dur-fast) var(--ease-out), + border-color var(--dur-fast) var(--ease-out); +} +a:hover { + color: var(--aus-bright-cyan); + border-bottom-color: currentColor; +} +a:focus-visible { + outline: none; + box-shadow: var(--glow-blue); + border-radius: var(--radius-xs); +} + +code, kbd, samp, pre { + font-family: var(--font-mono); + font-size: 0.92em; +} + +code { + background: var(--bg-1); + color: var(--aus-bright-cyan); + padding: 1px 6px; + border-radius: var(--radius-sm); + border: 1px solid var(--border-subtle); +} + +pre { + background: var(--bg-1); + color: var(--fg-1); + padding: var(--sp-5); + border-radius: var(--radius-md); + border: 1px solid var(--border-subtle); + overflow-x: auto; + line-height: var(--lh-normal); +} +pre code { + background: transparent; + border: 0; + padding: 0; + color: inherit; +} + +kbd { + background: var(--bg-2); + color: var(--fg-0); + border: 1px solid var(--border-default); + border-bottom-width: 2px; + padding: 1px 6px; + border-radius: var(--radius-sm); + font-size: var(--fs-2xs); + box-shadow: 0 1px 0 rgba(0,0,0,0.3); +} + +hr { + border: 0; + height: 1px; + background: var(--border-subtle); + margin: var(--sp-7) 0; +} + +::selection { + background: rgba(99, 136, 216, 0.35); + color: var(--fg-0); +} + +::placeholder { + color: var(--fg-muted); +} + +/* Eyebrow / label */ +.eyebrow { + font-family: var(--font-mono); + font-size: var(--fs-3xs); + text-transform: uppercase; + letter-spacing: var(--tracking-caps); + color: var(--aus-cyan); + font-weight: var(--fw-medium); +} diff --git a/home_root/.claude/skills/australis-design/preview/_card.css b/home_root/.claude/skills/australis-design/preview/_card.css new file mode 100644 index 0000000..555ce53 --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/_card.css @@ -0,0 +1,49 @@ +/* Shared shell for preview cards. Cards are 700×variable, dark canvas. */ +@import url("../colors_and_type.css"); + +* { box-sizing: border-box; } + +html, body { + margin: 0; + padding: 0; + background: var(--bg-0); + width: 700px; + overflow: hidden; +} + +.card { + width: 700px; + padding: 24px; + background: var(--bg-0); + color: var(--fg-1); + font-family: var(--font-sans); +} + +.row { display: flex; } +.col { display: flex; flex-direction: column; } +.gap-1 { gap: 4px; } .gap-2 { gap: 8px; } .gap-3 { gap: 12px; } +.gap-4 { gap: 16px; } .gap-5 { gap: 20px; } .gap-6 { gap: 24px; } + +.swatch { + border-radius: var(--radius-sm); + border: 1px solid rgba(255,255,255,0.04); +} +.swatch-label { + font-family: var(--font-mono); + font-size: 11px; + color: var(--fg-2); + letter-spacing: 0.02em; +} +.swatch-name { + font-family: var(--font-sans); + font-size: 12px; + color: var(--fg-0); + font-weight: 500; +} +.muted { + color: var(--fg-3); + font-size: 11px; + font-family: var(--font-mono); + letter-spacing: 0.04em; + text-transform: uppercase; +} diff --git a/home_root/.claude/skills/australis-design/preview/brand-icons.html b/home_root/.claude/skills/australis-design/preview/brand-icons.html new file mode 100644 index 0000000..675756f --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/brand-icons.html @@ -0,0 +1,37 @@ + +Iconography (Lucide) + + + +
+
+
plus
+
check
+
search
+
menu
+
download
+
settings
+
message
+
user
+ +
file
+
folder
+
terminal
+
code
+
bell
+
clock
+
heart
+
bookmark
+
+
Lucide · 1.75 stroke · 22px · current color · use sparingly, line over fill
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/brand-logo.html b/home_root/.claude/skills/australis-design/preview/brand-logo.html new file mode 100644 index 0000000..57633d3 --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/brand-logo.html @@ -0,0 +1,24 @@ + +Logo + + + +
+
+
+
Australis
+
logo-wordmark.svgon bg-0
+
+
+
Australis mark
+
logo-mark.svgon bright-white
+
+
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/brand-syntax.html b/home_root/.claude/skills/australis-design/preview/brand-syntax.html new file mode 100644 index 0000000..175e0e0 --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/brand-syntax.html @@ -0,0 +1,25 @@ + +Syntax Mapping + + + +
+ + + + + + + + + +
--syn-keywordkeywordconst · return · if#9d78ff
--syn-functionfunction · typerender() · paint()#6388d8
--syn-stringstring'australis'#16b866
--syn-numbernumber-77.85 · 0xff#42dcd1
--syn-constantconstantLATITUDE · PI#e1c631
--syn-tagtag · attribute<section>#00b1a8
--syn-commentcomment// note this#6e7882
--syn-errorerror · diff-delundefined#ff491a
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/colors-aurora.html b/home_root/.claude/skills/australis-design/preview/colors-aurora.html new file mode 100644 index 0000000..d2e3e4b --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/colors-aurora.html @@ -0,0 +1,23 @@ + +Aurora — Primary Colors + + + +
+
Aurora · primary · use generously · order: blue → cyan → green
+
+
Blue
#6388d8
+
Bright Blue
#a4c4ff
+
Cyan
#00b1a8
+
Bright Cyan
#42dcd1
+
Green
#16b866
+
Bright Green
#51e08a
+
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/colors-dawn.html b/home_root/.claude/skills/australis-design/preview/colors-dawn.html new file mode 100644 index 0000000..a48bd87 --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/colors-dawn.html @@ -0,0 +1,23 @@ + +Dawn — Accent Colors + + + +
+
Dawn · accent · use sparingly
+
+
Red
#ff491a
+
Bright Red
#ff854f
+
Yellow
#e1c631
+
Bright Yellow
#ffe14e
+
Magenta
#9d78ff
+
Bright Magenta
#d8adff
+
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/colors-ice.html b/home_root/.claude/skills/australis-design/preview/colors-ice.html new file mode 100644 index 0000000..3257cb3 --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/colors-ice.html @@ -0,0 +1,35 @@ + +Ice — Main Surface Colors + + + +
+
+
+
Blackbg
+
#222531
+
+
+
Whitefg
+
#a9bcc3
+
+
+
Bright Whitehighlight
+
#cce7ec
+
+
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/colors-sea.html b/home_root/.claude/skills/australis-design/preview/colors-sea.html new file mode 100644 index 0000000..13d4f80 --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/colors-sea.html @@ -0,0 +1,29 @@ + +Sea — Neutral Scale + + + +
+
Sea · neutral scale · cool blue → green tint as it brightens
+
+
L15
#222531
+
L25
#373b46
+
L30
#414751
+
L40
#565f69
+
L50
#6e7882
+
L60
#86929d
+
L70
#9daeb6
+
L75
#a9bcc3
+
L80
#b3cbcf
+
L90
#cce7ec
+
+
BlackDark 30 / 40 / 50 / 60Bright 70 / 80 / 90
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/colors-semantic.html b/home_root/.claude/skills/australis-design/preview/colors-semantic.html new file mode 100644 index 0000000..672a6a0 --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/colors-semantic.html @@ -0,0 +1,40 @@ + +Semantic / Status Colors + + + +
+
+
Info — informational--status-info
+
Success — operation complete--status-success
+
+
+
Warning — review needed--status-warning
+
Danger — destructive / error--status-danger
+
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/comp-badges.html b/home_root/.claude/skills/australis-design/preview/comp-badges.html new file mode 100644 index 0000000..61b7d0f --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/comp-badges.html @@ -0,0 +1,51 @@ + +Badges & Tags + + + +
+
+ Status + Live + Deploying + Warning + Failed + Idle +
+
+ Counter + v1.2.0 + beta + edge + +12 +
+
+ Tag + typescript + terminal + aurora + v18.3.1 +
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/comp-buttons.html b/home_root/.claude/skills/australis-design/preview/comp-buttons.html new file mode 100644 index 0000000..7e77682 --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/comp-buttons.html @@ -0,0 +1,50 @@ + +Buttons + + + +
+
+ Primary + + + + +
+
+ Secondary + + + + +
+
+ Status + + + +
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/comp-cards.html b/home_root/.claude/skills/australis-design/preview/comp-cards.html new file mode 100644 index 0000000..ada1021 --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/comp-cards.html @@ -0,0 +1,36 @@ + +Cards + + + +
+
+
+
+

Standard card

+

Default surface for grouping content. Subtle border, level-2 shadow, level-1 background.

+
--bg-1radius-lg
+
+
+
+

Featured card

+

Add a 2px aurora top-edge to single out a primary item without changing fill.

+
border-top: blueshadow-2
+
+
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/comp-controls.html b/home_root/.claude/skills/australis-design/preview/comp-controls.html new file mode 100644 index 0000000..f38f529 --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/comp-controls.html @@ -0,0 +1,49 @@ + +Toggles & Controls + + + +
+
Checkbox + Off + ✓On +
+
Radio + Option A + Option B +
+
Switch + Off + On +
+
Slider + + 0.60 +
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/comp-editor.html b/home_root/.claude/skills/australis-design/preview/comp-editor.html new file mode 100644 index 0000000..2e8d0b8 --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/comp-editor.html @@ -0,0 +1,52 @@ + +Code Editor + + + +
+
+
+
aurora.ts
+
tokens.css
+
README.md
+
+
+
1
2
3
4
5
6
7
+
+
// Render the southern sky
+
import { paint } from './aurora';
+
+
export const LATITUDE = -77.85;
+
export function render(name: string) {
+
  return paint(name, LATITUDE);
+
}
+
+
+
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/comp-inputs.html b/home_root/.claude/skills/australis-design/preview/comp-inputs.html new file mode 100644 index 0000000..98c257a --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/comp-inputs.html @@ -0,0 +1,35 @@ + +Inputs + + + +
+
+
We'll never share it.
+
3 of 32 chars used.
+
Use 8+ characters with mixed case.
+
Inherited from workspace.
+
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/comp-menu.html b/home_root/.claude/skills/australis-design/preview/comp-menu.html new file mode 100644 index 0000000..fa75c00 --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/comp-menu.html @@ -0,0 +1,47 @@ + +Menu & List + + + +
+
+ +
+
Commits — main
+
a3f2d fix: token regression2m
+
9b1c0 feat: aurora glow14m
+
52ee7 docs: usage rules1h
+
+
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/comp-terminal.html b/home_root/.claude/skills/australis-design/preview/comp-terminal.html new file mode 100644 index 0000000..dd4ad3f --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/comp-terminal.html @@ -0,0 +1,62 @@ + +Terminal Surface + + + +
+
+
+
+ aurora ~/projects/australis · zsh +
+
+ ➜ australis build --watch + # compiling 24 modules… + ✓ tokens compiled (184ms) + ✓ ui-kit bundled (412ms) + ! 2 deprecated tokens — see migration.md + ✗ assets/logo.svg not found + ➜ +
+
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/spacing-radii.html b/home_root/.claude/skills/australis-design/preview/spacing-radii.html new file mode 100644 index 0000000..739df9b --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/spacing-radii.html @@ -0,0 +1,27 @@ + +Radii + + + +
+
+
none0
+
xs2
+
sm4
+
md6
+
lg10
+
xl14
+
pill∞
+
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/spacing-scale.html b/home_root/.claude/skills/australis-design/preview/spacing-scale.html new file mode 100644 index 0000000..f3baf6e --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/spacing-scale.html @@ -0,0 +1,25 @@ + +Spacing + + + +
+
--sp-1 4px
+
--sp-2 8px
+
--sp-3 12px
+
--sp-4 16px
+
--sp-5 20px
+
--sp-6 24px
+
--sp-7 32px
+
--sp-8 40px
+
--sp-9 48px
+
--sp-1064px
+
--sp-1180px
+
--sp-1296px
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/spacing-shadows.html b/home_root/.claude/skills/australis-design/preview/spacing-shadows.html new file mode 100644 index 0000000..d56b162 --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/spacing-shadows.html @@ -0,0 +1,30 @@ + +Shadow & Glow + + + +
+
+
shadow-1
+
shadow-2
+
shadow-3
+
shadow-4
+ +
glow-blue
+
glow-cyan
+
glow-green
+
inset
+
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/type-body.html b/home_root/.claude/skills/australis-design/preview/type-body.html new file mode 100644 index 0000000..78ca9d1 --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/type-body.html @@ -0,0 +1,22 @@ + +Type · Body & UI + + + +
+
+
// EYEBROW · MONO 11/UC.eyebrow
+
A southern sky, rendered in pixels.Lead · 17 / 500
+
Body copy is Inter at 15px with a 1.6 line height. It carries longform reading on dashboards, docs, and settings.Body · 15 / 400
+
Secondary text — captions, helper copy, metadata.Small · 13 / 400
+
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/type-display.html b/home_root/.claude/skills/australis-design/preview/type-display.html new file mode 100644 index 0000000..04c9826 --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/type-display.html @@ -0,0 +1,27 @@ + +Type · Display + + + +
+
+
+ Aurora Australis + Display · 54 / 600 +
+
+ Cool by design. + H1 · 38 / 600 +
+
+ Section heading + H3 · 24 / 500 +
+
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/type-mono.html b/home_root/.claude/skills/australis-design/preview/type-mono.html new file mode 100644 index 0000000..c4a9f7c --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/type-mono.html @@ -0,0 +1,31 @@ + +Type · Mono & Code + + + +
+
+// JetBrains Mono · 13.5 / 1.6 +const aurora = render('australis', { lat: -77.85 }); +if (aurora.visible()) screen.paint(#6388d8); +$ australis --watch # reload on change +
+
--font-mono · JetBrains Monokw · fn · str · num · com
+
+ diff --git a/home_root/.claude/skills/australis-design/preview/type-scale.html b/home_root/.claude/skills/australis-design/preview/type-scale.html new file mode 100644 index 0000000..5b3c885 --- /dev/null +++ b/home_root/.claude/skills/australis-design/preview/type-scale.html @@ -0,0 +1,27 @@ + +Type · Scale + + + +
+ + + + + + + + + + + + +
--fs-6xl64Aa Bb 64
--fs-5xl48Aa Bb 48
--fs-4xl38Aa Bb 38
--fs-3xl30Aa Bb 30
--fs-2xl24Aa Bb 24
--fs-xl20Aa Bb 20
--fs-lg17Aa Bb 17
--fs-md15Aa Bb 15 (body)
--fs-sm14Aa Bb 14
--fs-xs13Aa Bb 13
--fs-2xs12Aa Bb 12
+
+ diff --git a/home_root/.claude/skills/australis-design/ui_kits/terminal/CommandPalette.jsx b/home_root/.claude/skills/australis-design/ui_kits/terminal/CommandPalette.jsx new file mode 100644 index 0000000..069ab17 --- /dev/null +++ b/home_root/.claude/skills/australis-design/ui_kits/terminal/CommandPalette.jsx @@ -0,0 +1,132 @@ +// CommandPalette — ⌘K overlay. Glass surface, blue focus ring. + +const CommandPalette = ({ open, onClose, onRun }) => { + const [q, setQ] = React.useState(''); + const [sel, setSel] = React.useState(0); + const inputRef = React.useRef(null); + + const items = React.useMemo(() => [ + { id: 'build', label: 'Build project', hint: '⌘B', kind: 'Action' }, + { id: 'deploy', label: 'Deploy to prod', hint: '⌘D', kind: 'Action' }, + { id: 'theme', label: 'Theme: Australis Dark', hint: '⌘T', kind: 'Setting' }, + { id: 'tokens', label: 'Open tokens.css', hint: 'go', kind: 'File' }, + { id: 'aurora', label: 'Open aurora.ts', hint: 'go', kind: 'File' }, + { id: 'sign', label: 'Sign out', hint: '', kind: 'Action', danger: true }, + ], []); + + const filtered = items.filter(i => i.label.toLowerCase().includes(q.toLowerCase())); + + React.useEffect(() => { + if (open && inputRef.current) inputRef.current.focus(); + setQ(''); setSel(0); + }, [open]); + + React.useEffect(() => { + if (!open) return; + const onKey = (e) => { + if (e.key === 'Escape') onClose(); + if (e.key === 'ArrowDown') { e.preventDefault(); setSel(s => Math.min(s + 1, filtered.length - 1)); } + if (e.key === 'ArrowUp') { e.preventDefault(); setSel(s => Math.max(s - 1, 0)); } + if (e.key === 'Enter' && filtered[sel]) { onRun(filtered[sel]); onClose(); } + }; + window.addEventListener('keydown', onKey); + return () => window.removeEventListener('keydown', onKey); + }, [open, sel, filtered, onClose, onRun]); + + if (!open) return null; + + return ( +
+
e.stopPropagation()}> +
+ + { setQ(e.target.value); setSel(0); }} + placeholder="Type a command…" + style={cpStyles.input} + /> + esc +
+
+ {filtered.length === 0 && ( +
No matches.
+ )} + {filtered.map((it, i) => ( +
setSel(i)} + onClick={() => { onRun(it); onClose(); }} + style={{ + ...cpStyles.item, + background: i === sel ? 'rgba(99,136,216,0.18)' : 'transparent', + color: i === sel ? '#a4c4ff' : (it.danger ? '#ff854f' : 'var(--fg-1)'), + }}> + + {it.label} + {it.kind} + {it.hint && {it.hint}} +
+ ))} +
+
+
+ ); +}; + +const cpStyles = { + scrim: { + position: 'absolute', inset: 0, + background: 'rgba(34,37,49,0.72)', + backdropFilter: 'blur(4px)', + display: 'flex', alignItems: 'flex-start', justifyContent: 'center', + paddingTop: '15vh', + zIndex: 100, + }, + panel: { + width: 540, + background: 'rgba(55,59,70,0.85)', + backdropFilter: 'blur(16px)', + border: '1px solid #565f69', + borderRadius: 10, + boxShadow: '0 24px 64px rgba(10,12,18,0.6), 0 8px 16px rgba(10,12,18,0.45)', + overflow: 'hidden', + }, + head: { + display: 'flex', alignItems: 'center', gap: 10, + padding: '12px 14px', + borderBottom: '1px solid #414751', + }, + input: { + flex: 1, background: 'transparent', border: 0, outline: 'none', + color: 'var(--fg-0)', + fontFamily: 'var(--font-sans)', fontSize: 14, + }, + esc: { + fontFamily: 'var(--font-mono)', fontSize: 10, + color: 'var(--fg-3)', background: '#1b1e28', + padding: '2px 6px', borderRadius: 4, border: '1px solid #414751', + }, + list: { padding: 6, maxHeight: 360, overflowY: 'auto' }, + item: { + display: 'flex', alignItems: 'center', gap: 10, + padding: '8px 10px', + borderRadius: 5, + fontSize: 13, + cursor: 'pointer', + }, + kind: { + fontFamily: 'var(--font-mono)', fontSize: 10, + color: 'var(--fg-3)', + textTransform: 'uppercase', letterSpacing: '0.06em', + }, + hint: { + fontFamily: 'var(--font-mono)', fontSize: 10, + color: 'var(--fg-3)', background: '#1b1e28', + padding: '2px 6px', borderRadius: 4, border: '1px solid #414751', + }, + empty: { padding: 16, fontSize: 13, color: 'var(--fg-3)' }, +}; + +window.CommandPalette = CommandPalette; diff --git a/home_root/.claude/skills/australis-design/ui_kits/terminal/Editor.jsx b/home_root/.claude/skills/australis-design/ui_kits/terminal/Editor.jsx new file mode 100644 index 0000000..aacc752 --- /dev/null +++ b/home_root/.claude/skills/australis-design/ui_kits/terminal/Editor.jsx @@ -0,0 +1,85 @@ +// Editor — tabs + gutter + syntax-highlighted code. + +const Editor = ({ openFiles, activeFile, onCloseFile, onSelectFile, fileContent }) => { + return ( +
+
+ {openFiles.map(f => { + const active = f === activeFile; + return ( +
onSelectFile(f)} + > + + {f.split('/').pop()} + { e.stopPropagation(); onCloseFile(f); }} + >× +
+ ); + })} +
+
+ +
+
+ {(fileContent[activeFile] || []).map((_, i) => ( +
{i + 1}
+ ))} +
+
+ {(fileContent[activeFile] || []).map((line, i) => ( +
+ ))} +
+
+
+ ); +}; + +const edStyles = { + root: { flex: 1, display: 'flex', flexDirection: 'column', + background: '#1b1e28', minWidth: 0 }, + tabs: { + display: 'flex', background: '#222531', + borderBottom: '1px solid #373b46', overflow: 'hidden', + }, + tab: { + display: 'flex', alignItems: 'center', gap: 8, + padding: '8px 14px', + fontFamily: 'var(--font-mono)', fontSize: 12, + color: 'var(--fg-3)', + borderRight: '1px solid #373b46', + cursor: 'pointer', + }, + tabActive: { + background: '#1b1e28', + color: 'var(--fg-0)', + boxShadow: 'inset 0 2px 0 #6388d8', + }, + tabSpacer: { flex: 1, borderBottom: '1px solid #373b46' }, + close: { + fontSize: 14, color: 'var(--fg-3)', + width: 14, height: 14, lineHeight: '12px', textAlign: 'center', + borderRadius: 3, + }, + body: { flex: 1, display: 'flex', overflow: 'auto', + fontFamily: 'var(--font-mono)', fontSize: 13.5, lineHeight: 1.7 }, + gutter: { + padding: '14px 12px 14px 18px', + color: '#414751', + textAlign: 'right', + userSelect: 'none', + background: '#1b1e28', + borderRight: '1px solid #2a2e38', + fontSize: 12.5, + }, + code: { flex: 1, padding: '14px 20px', whiteSpace: 'pre' }, + line: {}, +}; + +window.Editor = Editor; diff --git a/home_root/.claude/skills/australis-design/ui_kits/terminal/Icon.jsx b/home_root/.claude/skills/australis-design/ui_kits/terminal/Icon.jsx new file mode 100644 index 0000000..1bf9e08 --- /dev/null +++ b/home_root/.claude/skills/australis-design/ui_kits/terminal/Icon.jsx @@ -0,0 +1,45 @@ +// Inline Lucide-style icons. 24×24 viewBox, 1.75 stroke, currentColor, no fill. +// Keep the set small — add icons as the kit grows. + +const Icon = ({ name, size = 18, style }) => { + const props = { + width: size, height: size, viewBox: "0 0 24 24", + fill: "none", stroke: "currentColor", + strokeWidth: 1.75, strokeLinecap: "round", strokeLinejoin: "round", + style, + }; + switch (name) { + case "search": return ; + case "chevron-r": return ; + case "chevron-d": return ; + case "file": return ; + case "folder": return ; + case "terminal": return ; + case "settings": return ; + case "git-branch": return ; + case "play": return ; + case "x": return ; + case "check": return ; + case "alert": return ; + case "command": return ; + case "circle": return ; + case "plus": return ; + case "logo": return ( + + + + + + + + + + + + + ); + default: return null; + } +}; + +window.Icon = Icon; diff --git a/home_root/.claude/skills/australis-design/ui_kits/terminal/README.md b/home_root/.claude/skills/australis-design/ui_kits/terminal/README.md new file mode 100644 index 0000000..0146b73 --- /dev/null +++ b/home_root/.claude/skills/australis-design/ui_kits/terminal/README.md @@ -0,0 +1,26 @@ +# Australis — Terminal UI Kit + +The signature surface for Australis: a developer tool combining a terminal, a code editor, a file sidebar, and a status bar. This is what the system was built for. + +## Files + +- `index.html` — interactive demo wiring everything together +- `Sidebar.jsx` — file tree + workspace switcher +- `Editor.jsx` — tabbed code editor with syntax tokens +- `Terminal.jsx` — bottom panel terminal with prompt + output +- `StatusBar.jsx` — bottom rail (branch, syntax, line/col) +- `CommandPalette.jsx` — ⌘K palette overlay +- `Icon.jsx` — Lucide-style inline icons (1.75 stroke, currentColor) + +## What's interactive + +- Click sidebar files to switch editor tabs +- Click the workspace pill in the top-left to cycle workspaces +- Type into the terminal prompt and hit `Enter` — outputs are faked but feel right +- Press `⌘K` (or click the search field) to open the command palette +- Hover/focus states honor the system + +## Visual sources + +- `colors_and_type.css` — all tokens +- `README.md` (root) — visual foundations and content rules diff --git a/home_root/.claude/skills/australis-design/ui_kits/terminal/Sidebar.jsx b/home_root/.claude/skills/australis-design/ui_kits/terminal/Sidebar.jsx new file mode 100644 index 0000000..c128704 --- /dev/null +++ b/home_root/.claude/skills/australis-design/ui_kits/terminal/Sidebar.jsx @@ -0,0 +1,131 @@ +// Sidebar — workspace switcher + file tree. + +const Sidebar = ({ workspace, workspaces, onCycleWorkspace, openFile, activeFile, onOpenFile }) => { + const ws = workspaces[workspace]; + return ( + + ); +}; + +const TreeNode = ({ node, depth, activeFile, onOpenFile }) => { + const [open, setOpen] = React.useState(node.open !== false); + const isFile = !node.children; + const active = activeFile === node.path; + + return ( + <> +
isFile ? onOpenFile(node.path) : setOpen(o => !o)} + > + {!isFile && } + {isFile && } + + {node.name} + {node.modified && ●} +
+ {!isFile && open && node.children.map(c => ( + + ))} + + ); +}; + +const ssStyles = { + root: { + width: 260, flex: '0 0 260px', + background: '#1f222d', + borderRight: '1px solid #373b46', + display: 'flex', flexDirection: 'column', + fontFamily: 'var(--font-sans)', + color: 'var(--fg-1)', + }, + ws: { + display: 'flex', alignItems:'center', justifyContent:'space-between', + padding: '12px 14px', + background: 'transparent', border: 0, borderBottom: '1px solid #373b46', + color: 'var(--fg-0)', + cursor: 'pointer', textAlign: 'left', + fontFamily: 'var(--font-sans)', + }, + wsName: { fontSize: 14, fontWeight: 600, letterSpacing: '-0.005em' }, + wsHint: { + fontFamily: 'var(--font-mono)', fontSize: 10, + color: 'var(--fg-3)', background: '#1b1e28', + padding: '2px 6px', borderRadius: 4, border: '1px solid #414751', + }, + search: { + display: 'flex', alignItems:'center', gap: 8, + margin: '10px 12px', + padding: '6px 10px', + background: '#1b1e28', + border: '1px solid #414751', + borderRadius: 6, + }, + searchInput: { + flex: 1, background: 'transparent', border: 0, outline: 'none', + color: 'var(--fg-1)', fontFamily: 'var(--font-sans)', fontSize: 12, + }, + kbd: { + fontFamily: 'var(--font-mono)', fontSize: 10, + color: 'var(--fg-3)', + }, + head: { + fontFamily: 'var(--font-mono)', fontSize: 10, + textTransform: 'uppercase', letterSpacing: '0.08em', + color: 'var(--fg-3)', + padding: '8px 14px 4px', + }, + tree: { flex: 1, overflowY: 'auto', paddingBottom: 8 }, + row: { + display: 'flex', alignItems: 'center', gap: 6, + height: 26, padding: '0 10px 0 8px', + fontSize: 13, + cursor: 'pointer', + userSelect: 'none', + }, + name: { flex: 1, whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }, + modified: { color:'#42dcd1', fontSize: 12 }, + foot: { + display:'flex', alignItems:'center', gap:8, + padding: '10px 14px', + borderTop: '1px solid #373b46', + fontSize: 12, color: 'var(--fg-2)', + }, +}; + +window.Sidebar = Sidebar; diff --git a/home_root/.claude/skills/australis-design/ui_kits/terminal/StatusBar.jsx b/home_root/.claude/skills/australis-design/ui_kits/terminal/StatusBar.jsx new file mode 100644 index 0000000..49150b9 --- /dev/null +++ b/home_root/.claude/skills/australis-design/ui_kits/terminal/StatusBar.jsx @@ -0,0 +1,44 @@ +// StatusBar — bottom rail. Mono, dense, 24px tall. + +const StatusBar = ({ branch, problems, position, syntax }) => ( +
+
+ + {branch} + + + {problems.errors} + + + {problems.warnings} + +
+
+ {syntax} + UTF-8 + LF + {position} + + live + +
+
+); + +const sbStyles = { + root: { + height: 26, flex: '0 0 26px', + display: 'flex', justifyContent: 'space-between', + padding: '0 14px', + background: '#222531', + borderTop: '1px solid #373b46', + fontFamily: 'var(--font-mono)', fontSize: 11, + color: 'var(--fg-2)', + letterSpacing: '0.03em', + }, + left: { display:'flex', alignItems:'center', gap: 14 }, + right: { display:'flex', alignItems:'center', gap: 14 }, + cell: { display:'flex', alignItems:'center', gap: 5 }, +}; + +window.StatusBar = StatusBar; diff --git a/home_root/.claude/skills/australis-design/ui_kits/terminal/Terminal.jsx b/home_root/.claude/skills/australis-design/ui_kits/terminal/Terminal.jsx new file mode 100644 index 0000000..fc693ea --- /dev/null +++ b/home_root/.claude/skills/australis-design/ui_kits/terminal/Terminal.jsx @@ -0,0 +1,88 @@ +// Terminal — bottom panel, prompt + scrollback. + +const Terminal = ({ lines, onCommand }) => { + const [input, setInput] = React.useState(''); + const scrollRef = React.useRef(null); + + React.useEffect(() => { + if (scrollRef.current) { + scrollRef.current.scrollTop = scrollRef.current.scrollHeight; + } + }, [lines]); + + const submit = (e) => { + e.preventDefault(); + if (!input.trim()) return; + onCommand(input); + setInput(''); + }; + + return ( +
+
+ + terminal · zsh + + aurora ~/projects/australis +
+
+ {lines.map((ln, i) => ( +
+ ))} +
+ ➜ + setInput(e.target.value)} + placeholder="try: build, deploy, theme, help" + style={tmStyles.input} + autoFocus + /> +
+
+
+ ); +}; + +const tmStyles = { + root: { + height: 220, flex: '0 0 220px', + background: '#1b1e28', + borderTop: '1px solid #373b46', + display: 'flex', flexDirection: 'column', + }, + head: { + display: 'flex', alignItems: 'center', gap: 8, + padding: '6px 14px', + background: '#222531', + borderBottom: '1px solid #373b46', + fontFamily: 'var(--font-mono)', fontSize: 11, + color: 'var(--fg-3)', + letterSpacing: '0.04em', + }, + title: { color: 'var(--fg-2)' }, + spacer: { flex: 1 }, + host: { color: 'var(--fg-3)' }, + body: { + flex: 1, overflowY: 'auto', + padding: '10px 18px 14px', + fontFamily: 'var(--font-mono)', fontSize: 13, + lineHeight: 1.65, + color: 'var(--fg-1)', + }, + line: { whiteSpace: 'pre-wrap' }, + promptRow: { + display: 'flex', alignItems: 'center', gap: 8, + marginTop: 2, + }, + prompt: { color: '#42dcd1' }, + input: { + flex: 1, background: 'transparent', border: 0, outline: 'none', + fontFamily: 'var(--font-mono)', fontSize: 13, + color: 'var(--fg-0)', + caretColor: '#42dcd1', + }, +}; + +window.Terminal = Terminal; diff --git a/home_root/.claude/skills/australis-design/ui_kits/terminal/index.html b/home_root/.claude/skills/australis-design/ui_kits/terminal/index.html new file mode 100644 index 0000000..03e3d7e --- /dev/null +++ b/home_root/.claude/skills/australis-design/ui_kits/terminal/index.html @@ -0,0 +1,285 @@ + + + + + +Australis — Terminal UI Kit + + + + +
+ + + + + + + + + + + + + + + diff --git a/home_root/.claude/skills/australis-design/uploads/README.md b/home_root/.claude/skills/australis-design/uploads/README.md new file mode 100644 index 0000000..1b1a935 --- /dev/null +++ b/home_root/.claude/skills/australis-design/uploads/README.md @@ -0,0 +1,89 @@ +AustralisLogo + +# Australis Dark Color Theme + +The Australis Dark color theme is inspired by the Southern Lights: The Aurora Australis + +The theme consists of 16 terminal colors and a specification for usage. It is designed to be medium contrast and easy on the eyes as well as having an aesthetic appeal. + +It is based on the following design criteria: + +- All colors are cooler than neutral. +- With the exception of black, white and yellow, ANSI terminal colors have a perceived lab lightness of 65. _Bright_ variants have a lab lightness of 80. +- As neutral colors get brighter, they shift slightly towards green while maintaining the overall cool blue temperature. This is a design decision to give it an antactic ocean aurora theme. +- Overall contrast is medium to medium high to maintain eye comfort. + +## Ice - Main Colors + +These colors are the base colors. The background is a slightly cool light black without becoming too blue. As the primary colors increase in brightness, they start tinting more green. These are the primary colors that should make up the background and foreground. + +| ![#222531](https://placehold.co/100/222531/222531) | ![#a9bcc3](https://placehold.co/100/a9bcc3/a9bcc3) | ![#cce7ec](https://placehold.co/100/cce7ec/cce7ec) | +| :------------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: | +| #222531 | #a9bcc3 | #c7e7f9 | +| Background | Foreground | Highlight | +| Black | White | Bright White | + +## Aurora - Primary Colors + +These make up the bulk of the color volume for the theme. These colors can be used generously. By default, blue, cyan and green are used in that order of preference. Bright variants are used for highlighting purposes. + +| ![#6388D8](https://placehold.co/100/6388D8/6388D8) | ![#a4c4ff](https://placehold.co/100/a4c4ff/a4c4ff) | ![#00b1a8](https://placehold.co/100/00b1a8/00b1a8) | ![#42dcd1](https://placehold.co/100/42dcd1/42dcd1) | ![#16B866](https://placehold.co/100/16B866/16B866) | ![#51e08a](https://placehold.co/100/51e08a/51e08a) | +| :------------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: | +| #6388D8 | #a4c4ff | #00b1a8 | #42dcd1 | #16B866 | #51e08a | +| Blue | Bright Blue | Cyan | Bright Cyan | Green | Bright Green | + +## Dawn - Accent Colors + +These should be used sparingly for the theme. + +| ![#ff491a](https://placehold.co/100/ff491a/ff491a) | ![#ff854f](https://placehold.co/100/ff854f/ff854f) | ![#e1c631](https://placehold.co/100/e1c631/e1c631) | ![#FFE14E](https://placehold.co/100/FFE14E/FFE14E) | ![#9d78ff](https://placehold.co/100/9d78ff/9d78ff) | ![#d8adff](https://placehold.co/100/d8adff/d8adff) | +| :------------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: | +| #ff491a | #ff854f | #e1c631 | #FFE14E | #9d78ff | #d8adff | +| Red | Bright Red | Yellow | Bright Yellow | Magenta | Bright Magenta | + +## Sea - Neutral Contrast Colors + +These are neutral tones between black and bright white for adjusting contrast and for the representation of text on the colors and themes with varying degrees of contrast. Black, Bright Black, White and Bright White can be substituted for any of the contrast colors to give the desired contrast. Uses for the darks include low-contrast elements like comments. As with all neutral tones in the theme, green tint is progressively increased with brightness. + +### Darks + +| ![#222531](https://placehold.co/100/222531/222531) | ![#373b46](https://placehold.co/100/373b46/373b46) | ![#414751](https://placehold.co/100/414751/414751) | ![#565f69](https://placehold.co/100/565f69/565f69) | ![#6e7882](https://placehold.co/100/6e7882/6e7882) | ![#86929d](https://placehold.co/100/86929d/86929d) | +| :------------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: | +| #222531 | #373b46 | #414751 | #565f69 | #6e7882 | #86929d | +| Black (LAB 15) | Bright Black (LAB 25) | Dark_30 (LAB 30) | Dark_40 (LAB 40) | Dark_50 (Lab 50) | Dark_60 (Lab 60) | + +### Brights + +| ![#9daeb6](https://placehold.co/100/9daeb6/9daeb6) | ![#a9bcc3](https://placehold.co/100/a9bcc3/a9bcc3) | ![#b3cbcf](https://placehold.co/100/b3cbcf/b3cbcf) | ![#cce7ec](https://placehold.co/100/cce7ec/cce7ec) | +| :------------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: | +| #9daeb6 | #a9bcc3 | #b3cbcf | #cce7ec | +| Bright 70 (LAB 70) | White (Lab 75) | Bright_80 (LAB 80) | Bright White (LAB 90) | + +## All Colors and Hex Codes + +| Swatch | Hex | Color | +| -------------------------------------------------- | :-----: | :------------- | +| ![#222531](https://placehold.co/100/222531/222531) | #222531 | black | +| ![#373b46](https://placehold.co/100/373b46/373b46) | #373b46 | bright black | +| ![#a9bcc3](https://placehold.co/100/a9bcc3/a9bcc3) | #a9bcc3 | white | +| ![#cce7ec](https://placehold.co/100/cce7ec/cce7ec) | #cce7ec | bright white | +| ![#ff491a](https://placehold.co/100/ff491a/ff491a) | #ff491a | red | +| ![#ff854f](https://placehold.co/100/ff854f/ff854f) | #ff854f | bright red | +| ![#16B866](https://placehold.co/100/16B866/16B866) | #16B866 | green | +| ![#51e08a](https://placehold.co/100/51e08a/51e08a) | #51e08a | bright green | +| ![#6388D8](https://placehold.co/100/6388D8/6388D8) | #6388D8 | blue | +| ![#a4c4ff](https://placehold.co/100/a4c4ff/a4c4ff) | #a4c4ff | bright blue | +| ![#e1c631](https://placehold.co/100/e1c631/e1c631) | #e1c631 | yellow | +| ![#FFE14E](https://placehold.co/100/FFE14E/FFE14E) | #FFE14E | bright yellow | +| ![#9d78ff](https://placehold.co/100/9d78ff/9d78ff) | #9d78ff | magenta | +| ![#d8adff](https://placehold.co/100/d8adff/d8adff) | #d8adff | bright magenta | +| ![#00b1a8](https://placehold.co/100/00b1a8/00b1a8) | #00b1a8 | cyan | +| ![#42dcd1](https://placehold.co/100/42dcd1/42dcd1) | #42dcd1 | bright cyan | +| ![#414751](https://placehold.co/100/414751/414751) | #414751 | dark 30 | +| ![#565f69](https://placehold.co/100/565f69/565f69) | #565f69 | dark 40 | +| ![#6e7882](https://placehold.co/100/6e7882/6e7882) | #6e7882 | dark 50 | +| ![#86929d](https://placehold.co/100/86929d/86929d) | #86929d | dark 60 | +| ![#9daeb6](https://placehold.co/100/9daeb6/9daeb6) | #9daeb6 | bright 70 | +| ![#b3cbcf](https://placehold.co/100/b3cbcf/b3cbcf) | #b3cbcf | bright 80 | + +Copyright 2024 Vuong Hoang diff --git a/home_root/.gitconfig b/home_root/.gitconfig new file mode 100644 index 0000000..e597ad8 --- /dev/null +++ b/home_root/.gitconfig @@ -0,0 +1,5 @@ +[user] + name = Vuong Hoang + email = vh@phasefinal.com +[push] + followTags = true diff --git a/home_root/.local/bin/claude-config-dir-init b/home_root/.local/bin/claude-config-dir-init new file mode 100755 index 0000000..1054e7e --- /dev/null +++ b/home_root/.local/bin/claude-config-dir-init @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Seed a second Claude Code config dir that shares everything login-independent +# with ~/.claude (symlinks) but holds its own credentials and its own +# .claude.json (copied once, so MCP servers and onboarding carry over; /login +# then rebinds the account). Usage: claude-config-dir-init /abs/path/.claude- +set -euo pipefail +target="${1:?usage: claude-config-dir-init /abs/path}" +case "$target" in /*) ;; *) echo "use an absolute path (no ~ inside quotes)" >&2; exit 2;; esac +src="$HOME/.claude" +mkdir -p "$target" +shared=(CLAUDE.md CONTEXT.md skills plugins hooks agents commands settings.json settings.local.json keybindings.json statusline-command.sh bin projects projects-archive plans feedback) +for item in "${shared[@]}"; do + [ -e "$src/$item" ] || continue + if [ -e "$target/$item" ] && [ ! -L "$target/$item" ]; then echo "skip $item: real file already in $target" >&2; continue; fi + ln -sfn "$src/$item" "$target/$item" +done +if [ ! -e "$target/.claude.json" ] && [ -f "$HOME/.claude.json" ]; then cp "$HOME/.claude.json" "$target/.claude.json"; chmod 600 "$target/.claude.json"; fi +echo "seeded $target"; ls -la "$target" | sed -n '2,40p' +echo +echo "next: CLAUDE_CONFIG_DIR=\"$target\" claude → /login once; credentials land in $target/.credentials.json" diff --git a/home_root/.zshenv b/home_root/.zshenv new file mode 100644 index 0000000..7ada7e9 --- /dev/null +++ b/home_root/.zshenv @@ -0,0 +1,28 @@ +[ -f "$HOME/.cargo/env" ] && . "$HOME/.cargo/env" + +# user-level secrets (HF_TOKEN etc.) +[ -f "$HOME/.config/secrets/env.sh" ] && source "$HOME/.config/secrets/env.sh" + +# fleet CLIs (booth, secret symlinks) reachable from non-interactive ssh too +export PATH="$HOME/.local/bin:$HOME/bin:$PATH" + +# safe-rm (installed 2026-09-22, operator's call) — a wrapper that REFUSES to +# delete the ~25 protected system paths in /etc/safe-rm.conf: /, /bin, /etc, +# /home, /usr, /var and friends. Guards the rm -rf /usr class of mistake. +# +# ⚠ IT IS SET HERE AND NOT LEFT TO THE PACKAGE. safe-rm ships +# /etc/profile.d/safe-rm.sh, which /etc/profile walks correctly -- but Debian's +# /etc/zsh/zprofile is entirely commented out (0 non-comment lines), so a zsh +# LOGIN shell never sources /etc/profile and the hook never fires. Measured +# immediately after install: rm still resolved to /usr/bin/rm in this shell, in +# a fresh `zsh -l`, AND over ssh. Installed and inert. +# +# .zshenv is the right home because it is sourced for EVERY zsh invocation, +# including the non-interactive `ssh host ''` form that is how most fleet +# work actually runs -- the same reason ~/.local/bin is set here. +# +# ⚠ AND IT DOES NOT COVER THE MISTAKE THAT PROMPTED IT. safe-rm is a path +# blacklist, not a heuristic. Measured: it refuses `rm -rf /home`, and it +# deletes a file whose path came from an unset variable without complaint. The +# variable-path habit is still guarded only by discipline and `set -u`. +[ -d /usr/share/safe-rm/bin ] && export PATH="/usr/share/safe-rm/bin:$PATH" diff --git a/link-dotfiles b/link-dotfiles index 576b59f..31aed82 100755 --- a/link-dotfiles +++ b/link-dotfiles @@ -10,11 +10,41 @@ # # Windows / PowerShell: run ./link-dotfiles.ps1 instead (stow has no native # Windows port; the .ps1 mirrors this with junctions + symlinks). +# +# `--check`: report drift and change nothing. Two kinds are caught. (1) A tracked +# file whose live copy is no longer a link into this repo: stow would refuse to +# stow over it, so the repo copy has silently gone stale. `sed -i` and any other +# write-temp-then-rename editor does this, and so can an app that rewrites its +# own config atomically. (2) A link into this repo whose target has been removed. +# Exits 1 on drift. set -euo pipefail repo="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$repo" +if [ "${1:-}" = "--check" ]; then + command -v stow >/dev/null 2>&1 || { echo "error: GNU stow not installed; run ./link-dotfiles once first." >&2; exit 2; } + drift=0 + for spec in "home_root:$HOME" "home_config:$HOME/.config"; do + pkg="${spec%%:*}"; target="${spec#*:}" + out="$(stow -n -v --target="$target" "$pkg" 2>&1 | grep -v 'simulation mode' || true)" + if [ -n "$out" ]; then + drift=1 + echo "✗ $pkg -> $target is not fully linked:" + printf '%s\n' "$out" | sed 's/^/ /' + fi + done + dangling="$(find "$HOME" "$HOME/.config" "$HOME/.claude" "$HOME/.claude/bin" "$HOME/.claude/skills" "$HOME/.local/bin" \ + -maxdepth 1 -xtype l -lname "*dotfiles/*" 2>/dev/null || true)" + if [ -n "$dangling" ]; then + drift=1 + echo "✗ links into dotfiles whose target is gone:" + printf '%s\n' "$dangling" | sed 's/^/ /' + fi + [ "$drift" -eq 0 ] && echo "✓ no drift: every tracked file is linked, and no dotfiles link dangles." + exit "$drift" +fi + # `--apps`: install all host CLI tools first, then link. Without it, this only # links (fast + idempotent). App install is delegated to the host-aware # lk-installers/install-apps.