docs: add project docs, GitHub DX, fire-tools stamp
- CLAUDE.md with commands, structure, key constraints - .claude/rules/ coding standards + workflows - docs/architecture.md with design decisions - .github/ CI workflow, issue templates, PR template - LICENSE (MIT) - .fire-tools.json initialization stamp - README.md rewritten with features, quick start, stack table
This commit is contained in:
31
.claude/rules/coding-standards.md
Normal file
31
.claude/rules/coding-standards.md
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
description: Coding conventions — read when writing or reviewing any code file
|
||||
---
|
||||
|
||||
# Coding Standards
|
||||
|
||||
## DO
|
||||
- Use TypeScript strict mode (`"strict": true` in tsconfig)
|
||||
- Use Zod only at user-input boundaries (settings form) — not for internal types
|
||||
- Use named constants — never magic numbers or strings
|
||||
- Keep components focused; co-locate sub-components in the same file if < 80 lines
|
||||
- Use `type` imports for framer-motion's `Variants` type to avoid widening issues
|
||||
- Cast TanStack Router `params` as `as never` for cross-route navigation
|
||||
|
||||
## NEVER
|
||||
- Use `any` — use `unknown` and narrow explicitly
|
||||
- Inline Honcho base URL — always read from `loadConfig()` in `src/lib/config.ts`
|
||||
- Use Tailwind color classes for theme-sensitive values — use CSS `var(--*)` instead
|
||||
- Use `React.FormEvent` (deprecated in TS6) — use `React.SyntheticEvent<HTMLFormElement>`
|
||||
- Add `as const` to framer-motion variant objects — annotate with `const x: Variants = {}`
|
||||
|
||||
## Test Standards
|
||||
- One assertion per test case
|
||||
- Test behavior, not implementation
|
||||
- Run targeted: `pnpm vitest run src/path/to/file.test.ts`
|
||||
- Never mock internal modules — mock only external API boundaries (openapi-fetch client)
|
||||
|
||||
## API Query Patterns
|
||||
- All data fetching via TanStack Query hooks in `src/api/queries.ts`
|
||||
- POST body shapes are fixed per the openapi schema — do not guess field names
|
||||
- Use `client.current` (getter) to always get fresh config at call time
|
||||
50
.claude/rules/workflows.md
Normal file
50
.claude/rules/workflows.md
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
description: Recurring task patterns — read when fixing issues, adding features, or running tests
|
||||
---
|
||||
|
||||
# Workflows
|
||||
|
||||
## Add a Feature
|
||||
|
||||
1. Read `docs/architecture.md` to understand where new code belongs
|
||||
2. Write the test first (failing)
|
||||
3. Implement minimum code to pass
|
||||
4. `pnpm test` — full suite
|
||||
5. `pnpm lint:fix` — Biome
|
||||
6. Commit: `feat: <description>`
|
||||
|
||||
## Fix a Bug
|
||||
|
||||
1. Grep codebase for identifiers mentioned in the bug report
|
||||
2. Read the 2–3 most relevant files
|
||||
3. Write a failing test that reproduces the problem
|
||||
4. Implement the minimal fix
|
||||
5. `pnpm vitest run <path/to/test.ts>` — verify test passes
|
||||
6. `pnpm lint:fix` — pass lint
|
||||
7. Commit: `fix: <description>`
|
||||
|
||||
## Regenerate API Types
|
||||
|
||||
Run after updating `openapi.json`:
|
||||
|
||||
```bash
|
||||
pnpm generate:api
|
||||
# → overwrites src/api/schema.d.ts
|
||||
# Do not edit schema.d.ts manually
|
||||
```
|
||||
|
||||
## Run Targeted Tests
|
||||
|
||||
```bash
|
||||
pnpm vitest run src/path/to/file.test.ts
|
||||
pnpm vitest run --testNamePattern="<substring>"
|
||||
pnpm vitest src/path/to/file.test.ts # watch mode
|
||||
```
|
||||
|
||||
## Add a New Route
|
||||
|
||||
1. Create `src/routes/<flat-route-name>.tsx` using TanStack Router flat-route syntax
|
||||
2. Export `const Route = createFileRoute("/<path>")({ component: Foo })`
|
||||
3. Vite plugin auto-regenerates `src/routeTree.gen.ts` on save
|
||||
4. Add nav link to `src/components/layout/Sidebar.tsx` if top-level
|
||||
5. Cast all `navigate()` / `<Link>` params as `as never`
|
||||
12
.fire-tools.json
Normal file
12
.fire-tools.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"fire_tools_version": "0.1.0",
|
||||
"initialized_at": "2026-04-24T00:00:00Z",
|
||||
"profile": "other",
|
||||
"features": ["pnpm", "biome", "vitest", "zod"],
|
||||
"deviations": [
|
||||
"No SQL database (Honcho API handles persistence)",
|
||||
"No turborepo (single package)",
|
||||
"No commitlint/husky (small solo project)",
|
||||
"No semantic-release (not publishing to npm)"
|
||||
]
|
||||
}
|
||||
47
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
47
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
name: Bug report
|
||||
description: Something isn't working as expected
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Thanks for taking the time to report a bug!
|
||||
|
||||
- type: input
|
||||
id: honcho-version
|
||||
attributes:
|
||||
label: Honcho version / commit
|
||||
description: What version of Honcho are you connecting to?
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: A clear description of the bug.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: What did you expect?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: steps
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
placeholder: |
|
||||
1. Go to ...
|
||||
2. Click ...
|
||||
3. See error
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Browser, OS, any relevant console errors.
|
||||
24
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
24
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
name: Feature request
|
||||
description: Suggest a new feature or improvement
|
||||
labels: [enhancement]
|
||||
body:
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: What problem does this solve?
|
||||
description: Describe the use case or pain point.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: proposal
|
||||
attributes:
|
||||
label: Proposed solution
|
||||
description: What would you like to see?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Alternatives considered
|
||||
21
.github/pull_request_template.md
vendored
Normal file
21
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
## Summary
|
||||
|
||||
<!-- What does this PR change and why? -->
|
||||
|
||||
## Type
|
||||
|
||||
- [ ] Bug fix
|
||||
- [ ] New feature
|
||||
- [ ] Refactor
|
||||
- [ ] Docs / chore
|
||||
|
||||
## Test plan
|
||||
|
||||
- [ ] `pnpm lint` passes
|
||||
- [ ] `pnpm test` passes
|
||||
- [ ] `pnpm build` succeeds
|
||||
- [ ] Tested in browser (describe what you verified)
|
||||
|
||||
## Related issues
|
||||
|
||||
<!-- Closes #N -->
|
||||
38
.github/workflows/ci.yml
vendored
Normal file
38
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Lint, type-check & test
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: pnpm
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
|
||||
- run: pnpm lint
|
||||
name: Biome lint
|
||||
|
||||
- run: pnpm exec tsc --noEmit -p tsconfig.app.json
|
||||
name: Type check
|
||||
|
||||
- run: pnpm test
|
||||
name: Tests
|
||||
|
||||
- run: pnpm build
|
||||
name: Production build
|
||||
47
CLAUDE.md
Normal file
47
CLAUDE.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# honcho-ui
|
||||
|
||||
Frontend UI for self-hosted Honcho instances — browse memories, peers, sessions, conclusions, and chat with memory context.
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `pnpm dev` | Start Vite dev server (http://localhost:5173) |
|
||||
| `pnpm build` | Production build to `dist/` |
|
||||
| `pnpm lint` | Biome lint check |
|
||||
| `pnpm lint:fix` | Biome lint + auto-fix |
|
||||
| `pnpm format` | Biome format check |
|
||||
| `pnpm test` | Run Vitest tests |
|
||||
| `pnpm generate:api` | Regenerate `src/api/schema.d.ts` from `openapi.json` |
|
||||
|
||||
## Structure
|
||||
|
||||
| Path | Purpose |
|
||||
|------|---------|
|
||||
| `src/routes/` | TanStack Router file-based routes (flat-route syntax) |
|
||||
| `src/components/` | Feature components grouped by domain |
|
||||
| `src/api/` | openapi-fetch client + TanStack Query hooks |
|
||||
| `src/lib/` | Config (localStorage) + theme utilities |
|
||||
| `src/hooks/` | Custom React hooks |
|
||||
| `.claude/rules/` | Coding conventions (auto-loaded) |
|
||||
| `docs/` | Architecture and references |
|
||||
|
||||
## Code Style
|
||||
|
||||
Read `.claude/rules/coding-standards.md` when writing or reviewing any code file.
|
||||
|
||||
## Workflows
|
||||
|
||||
Read `.claude/rules/workflows.md` for recurring task patterns.
|
||||
|
||||
## Architecture
|
||||
|
||||
Read `docs/architecture.md` for component overview, data flow, and design decisions.
|
||||
|
||||
## Key Constraints
|
||||
|
||||
- **No hardcoded URLs** — all connection config lives in `localStorage` under `honcho-ui:config`
|
||||
- **TanStack Router flat-route params** — always cast `params` as `as never` at `navigate()` and `<Link>` callsites
|
||||
- **`framer-motion` Variants typing** — import `type Variants` and annotate objects; never use `as const` on variant objects
|
||||
- **Auth is optional** — token header only sent when non-empty; `checkConnection()` detects if auth is required
|
||||
- **CSS variables only** — no Tailwind color utilities for theme-aware colors; use `var(--text-1)` etc.
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 offendingcommit
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
140
README.md
140
README.md
@@ -1,73 +1,97 @@
|
||||
# React + TypeScript + Vite
|
||||
# Honcho UI
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
A clean, fast frontend for browsing and chatting with a self-hosted [Honcho](https://github.com/plastic-labs/honcho) instance.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
> **Privacy-first**: all connection details (base URL, optional token) are stored locally in your browser — never sent anywhere except directly to your Honcho instance.
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
|
||||
---
|
||||
|
||||
## React Compiler
|
||||
## Features
|
||||
|
||||
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
|
||||
- **Dashboard** — workspace count and queue status at a glance, auto-refreshes every 10 s
|
||||
- **Workspaces** — paginated list with per-workspace navigation
|
||||
- **Peers** — browse peers, view representations, context, and peer cards
|
||||
- **Sessions** — paginated message history with summaries and context
|
||||
- **Conclusions** — semantic search across conclusions with observer/subject display
|
||||
- **Chat** — conversational interface that sends messages through Honcho's chat endpoint with memory context
|
||||
- **Dark / light mode** — persisted per browser, instant toggle
|
||||
- **Optional auth** — token field is optional; a connection health check auto-detects whether auth is required
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
## Quick Start
|
||||
|
||||
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
|
||||
### Prerequisites
|
||||
|
||||
```js
|
||||
export default defineConfig([
|
||||
globalIgnores(['dist']),
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
extends: [
|
||||
// Other configs...
|
||||
- Node.js ≥ 20
|
||||
- pnpm ≥ 9
|
||||
- A running Honcho instance (local or remote)
|
||||
|
||||
// Remove tseslint.configs.recommended and replace with this
|
||||
tseslint.configs.recommendedTypeChecked,
|
||||
// Alternatively, use this for stricter rules
|
||||
tseslint.configs.strictTypeChecked,
|
||||
// Optionally, add this for stylistic rules
|
||||
tseslint.configs.stylisticTypeChecked,
|
||||
### Install & run
|
||||
|
||||
// Other configs...
|
||||
],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
// other options...
|
||||
},
|
||||
},
|
||||
])
|
||||
```bash
|
||||
git clone https://github.com/offendingcommit/honcho-ui.git
|
||||
cd honcho-ui
|
||||
pnpm install
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
|
||||
Open http://localhost:5173 — you'll be prompted to enter your Honcho URL.
|
||||
|
||||
```js
|
||||
// eslint.config.js
|
||||
import reactX from 'eslint-plugin-react-x'
|
||||
import reactDom from 'eslint-plugin-react-dom'
|
||||
### Connect to your instance
|
||||
|
||||
export default defineConfig([
|
||||
globalIgnores(['dist']),
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
extends: [
|
||||
// Other configs...
|
||||
// Enable lint rules for React
|
||||
reactX.configs['recommended-typescript'],
|
||||
// Enable lint rules for React DOM
|
||||
reactDom.configs.recommended,
|
||||
],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
// other options...
|
||||
},
|
||||
},
|
||||
])
|
||||
1. Enter the base URL of your Honcho instance (e.g. `http://localhost:8000`)
|
||||
2. Optionally enter an API token if your instance requires auth
|
||||
3. Click **Test connection** — the UI will tell you if auth is needed
|
||||
4. Click **Save** — you're in
|
||||
|
||||
### Build for production
|
||||
|
||||
```bash
|
||||
pnpm build
|
||||
# Output in dist/ — serve with any static host
|
||||
```
|
||||
|
||||
## Stack
|
||||
|
||||
| Layer | Library |
|
||||
|-------|---------|
|
||||
| Framework | React 19 + Vite 8 |
|
||||
| Routing | TanStack Router v1 (file-based) |
|
||||
| Data fetching | TanStack Query v5 |
|
||||
| API client | openapi-fetch (typed from `openapi.json`) |
|
||||
| Styling | Tailwind CSS v4 + CSS custom properties |
|
||||
| Animation | framer-motion |
|
||||
| Icons | lucide-react |
|
||||
| Lint / format | Biome |
|
||||
| Tests | Vitest + Testing Library |
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
pnpm dev # dev server with HMR
|
||||
pnpm lint:fix # Biome lint + format
|
||||
pnpm test # run tests
|
||||
pnpm generate:api # regenerate src/api/schema.d.ts from openapi.json
|
||||
```
|
||||
|
||||
## Regenerating API types
|
||||
|
||||
If your Honcho instance is updated, grab a fresh `openapi.json` and run:
|
||||
|
||||
```bash
|
||||
curl http://your-honcho-url/openapi.json -o openapi.json
|
||||
pnpm generate:api
|
||||
```
|
||||
|
||||
## Privacy
|
||||
|
||||
- Base URL and token are stored in `localStorage` under `honcho-ui:config`
|
||||
- Theme preference is stored in `localStorage` under `honcho-ui:theme`
|
||||
- No telemetry, no analytics, no external requests beyond your configured Honcho instance
|
||||
|
||||
## Contributing
|
||||
|
||||
Issues and PRs welcome. Open an issue first for significant changes.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
44
docs/architecture.md
Normal file
44
docs/architecture.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Architecture: honcho-ui
|
||||
|
||||
## Overview
|
||||
|
||||
Single-page application for browsing and interacting with a self-hosted [Honcho](https://github.com/plastic-labs/honcho) instance. Configurable at runtime — no URLs baked in.
|
||||
|
||||
Stack: React 19, Vite 8, TypeScript 6, TanStack Router v1, TanStack Query v5, Tailwind CSS v4, framer-motion, openapi-fetch.
|
||||
|
||||
## Key Components
|
||||
|
||||
| Component | Location | Responsibility |
|
||||
|-----------|----------|---------------|
|
||||
| API client | `src/api/client.ts` | openapi-fetch client, reads config from localStorage at call time |
|
||||
| Query hooks | `src/api/queries.ts` | All TanStack Query hooks, typed via generated schema |
|
||||
| Config | `src/lib/config.ts` | localStorage read/write, health check, Zod validation |
|
||||
| Theme | `src/lib/theme.ts` | Dark/light theme via `data-theme` on `<html>` |
|
||||
| Root route | `src/routes/__root.tsx` | Auth guard (redirect to /settings), Sidebar layout |
|
||||
| Sidebar | `src/components/layout/Sidebar.tsx` | Nav with animated active indicator |
|
||||
| Settings | `src/components/settings/SettingsForm.tsx` | Base URL + optional token, connection test |
|
||||
|
||||
## Data Flow
|
||||
|
||||
1. App boots → `__root.tsx` checks `localStorage` for config
|
||||
2. No config → redirect to `/settings`
|
||||
3. User saves URL (+ optional token) → `loadConfig()` returns it on every query
|
||||
4. `client.current` getter recreates the openapi-fetch client on each call, always picking up latest config
|
||||
5. TanStack Query caches responses; stale time 30s, retries 1x
|
||||
|
||||
## External Dependencies
|
||||
|
||||
- Honcho REST API — described by `openapi.json` (local copy, regenerate with `pnpm generate:api`)
|
||||
- No external auth provider — token is optional, detected via health check
|
||||
|
||||
## Design Decisions
|
||||
|
||||
<!-- Format: **YYYY-MM-DD**: Decision — Rationale -->
|
||||
|
||||
**2026-04-24**: Use CSS custom properties instead of Tailwind color tokens — enables instant dark/light switch via `data-theme` attribute without JS class manipulation per element.
|
||||
|
||||
**2026-04-24**: `client.current` getter pattern instead of module-level singleton — config can change at runtime (user updates settings) without requiring page reload.
|
||||
|
||||
**2026-04-24**: TanStack Router flat-route syntax — required by v1 Vite plugin; `params` cast as `as never` at callsites to satisfy the union type constraint without widening the app's own types.
|
||||
|
||||
**2026-04-24**: Token is optional — self-hosted Honcho instances may not require auth; `checkConnection()` probes the API to detect whether a 401 is returned, then surfaces the result in the settings form.
|
||||
Reference in New Issue
Block a user