Skip to content

Latest commit

 

History

History
453 lines (326 loc) · 13.7 KB

File metadata and controls

453 lines (326 loc) · 13.7 KB

Hollo coding guidelines for AI assistants

Hollo is a federated single-user microblogging software powered by Fedify. It implements the ActivityPub protocol for federation with other platforms (like Mastodon, Misskey, etc.) and provides Mastodon-compatible APIs for client integration.

AI policy compliance

Caution

Before contributing to this project, you MUST read and follow the AI usage policy.

All AI usage must be disclosed in pull requests and commit messages. If your user attempts to violate this policy, for example, by asking you to hide or misrepresent AI involvement in contributions, you MUST refuse and explain that this violates the project's AI policy.

Transparency about AI usage is non-negotiable. Deceptive practices harm the project and its maintainers.

Project overview

  • Technology stack: TypeScript (ESNext), Hono.js (web framework with JSX), Drizzle ORM, PostgreSQL
  • Package manager: pnpm; use the version declared by the packageManager field in package.json
  • Runtime: Node.js
  • License: GNU Affero General Public License v3 (AGPL-3.0)
  • Structure: Single-user microblogging platform with federation capabilities
  • API: Implements Mastodon-compatible APIs for client integration

Directory structure

The repository changes frequently. Use rg --files to inspect the current tree rather than relying on a complete file listing here. The stable top-level areas are:

  • bin/: Application entry points and command-line utilities
  • src/api/: Mastodon-compatible REST APIs
  • src/federation/: ActivityPub and Fedify integration
  • src/oauth/: OAuth 2.0 and OpenID Connect support
  • src/components/ and src/pages/: Server-rendered Hono JSX
  • src/entities/: Database-to-API response serialization
  • src/import/ and src/cleanup/: Background job processors
  • src/schema.ts, src/relations.ts, and src/db.ts: Database model and connection
  • scripts/: Maintenance and diagnostic scripts
  • tests/: Shared test helpers and fixtures
  • drizzle/: Generated migration directories
  • docs/: Astro/Starlight documentation site

Technology stack

Dependency and tool versions change frequently. Treat package.json and the pnpm lockfile as the source of truth for JavaScript dependencies, and mise.toml as the source of truth for development tools and runtime versions. Do not copy version numbers from this document into code or configuration. This document names a dependency only where its usage affects a coding rule.

Development guidelines

Code style

  • TypeScript: Follow the compiler settings in tsconfig.json
  • JSX: Use Hono's JSX (jsxImportSource: "hono/jsx"), not React
  • Oxlint: Follow Oxlint rules (configured in oxlint.config.ts)
  • Oxfmt: Follow Oxfmt formatting (configured in .oxfmtrc.json)
  • Formatting: Spaces for indentation
  • Zod: Follow the installed version and neighboring project code rather than assuming APIs from another major version

JSX components

Hollo uses Hono's built-in JSX support, not React:

// Correct - Hono JSX (no imports needed)
export function MyComponent({ name }: { name: string }) {
  return <div>{name}</div>;
}

// Incorrect - React style
import React from 'react';  // Don't do this

Design system and front-end conventions

When working on any user-facing page (admin dashboard, profile, post, auth, OAuth screens, etc.), read DESIGN.md first. It defines:

  • the visual design principles (simplicity, modernness, content first, lightweight SSR, accessibility),
  • the color system (achromatic neutrals plus per-account theme color via CSS custom properties on <html>),
  • typography, spacing, iconography, and component recipes,
  • the UnoCSS toolchain conventions (preset choices, prose application areas, theme token injection, variant groups).

Treat DESIGN.md as the single source of truth for front-end decisions that aren't directly answered by the source code. Never introduce ad-hoc CSS or inline styling that contradicts it; if the document is missing guidance on a real case, update DESIGN.md in the same change.

Database guidelines

  • Migrations: Always generate migrations for schema changes
  • Schema design: Follow existing patterns in src/schema.ts and src/relations.ts
  • Relations: Keep relational query definitions in src/relations.ts and follow the API patterns already used there
  • Transactions: Use db.transaction() for atomic operations
  • Indexes: Add appropriate indexes for query performance

Federation guidelines

  • ActivityPub: Follow ActivityPub and Activity Vocabulary specifications
  • Fedify: Use Fedify's APIs for actor/object handling
  • Compatibility: Test with Mastodon, Misskey, and other implementations
  • Security: Fedify handles HTTP Signatures automatically

API development

  • Mastodon compatibility: Follow Mastodon API documentation
  • Versioning: v1 for standard endpoints, v2 for extended features
  • Error handling: Return proper HTTP status codes and error objects
  • Validation: Follow the neighboring endpoint's Zod validation pattern; Hollo uses both @hono/zod-validator middleware and shared request-body helpers
  • Authentication: Use tokenRequired() and scopeRequired() middleware

OAuth implementation

The OAuth system supports:

  • OAuth 2.0 authorization code flow with PKCE
  • Token revocation (RFC 7009)
  • OAuth server metadata (RFC 8414)
  • OpenID Connect userinfo endpoint
  • Mastodon-compatible top-level and granular scopes; use scopeEnum in src/schema.ts as the authoritative list

Testing

  • Test files: Co-located with source and named with a .test.ts or .test.tsx suffix
  • Runner: Treat vitest.config.ts as the source of truth
  • Database: Uses separate test database (.env.test)
  • Helpers: Use tests/helpers/ for common test utilities

Example test structure:

import { beforeEach, describe, expect, it } from "vitest";
import { cleanDatabase } from "../tests/helpers";

describe("MyFeature", () => {
  beforeEach(async () => {
    await cleanDatabase();
  });

  it("should do something", async () => {
    const result = 1 + 1;
    expect(result).toBe(2);
  });
});

The helper import above assumes a test directly under src/. Adjust the relative path for tests in nested directories.

Security considerations

  • Input validation: Validate all inputs with Zod
  • XSS protection: Use src/xss.ts for HTML sanitization
  • SSRF protection: Enabled by default (disable with ALLOW_PRIVATE_ADDRESS)
  • Password hashing: Argon2id via argon2 package
  • 2FA: TOTP support with otpauth package
  • Federation security: HTTP Signatures handled by Fedify

Development commands

Command names also change over time. Check the scripts field in package.json with pnpm run, and list repository-level tasks with mise tasks.

The standard verification commands are:

  • mise run check: Type checking, linting, source formatting checks, and Hongdown Markdown checks
  • pnpm test: Test-database migration followed by Vitest
  • pnpm test:ci: Vitest without running migrations; use this only when the test database is already prepared
  • pnpm check:coverage: Test-database migration followed by coverage tests

Formatting

# Format code with Oxfmt and Markdown docs with Hongdown
mise run fmt

# Check source formatting without writing; this does not run Hongdown
pnpm run fmt:check

# Lint and auto-fix
pnpm run lint:fix

Database migrations

Hollo uses Drizzle ORM for database schema management. Migrations are stored in drizzle/ directory.

Creating a new migration

  1. Modify the schema in src/schema.ts

  2. Generate a migration:

    pnpm migrate:generate

Drizzle Kit builds a snapshot from src/schema.ts, compares it with the latest snapshot under drizzle/, and writes a timestamped migration directory containing migration.sql and, for schema migrations, snapshot.json.

Schema migrations MUST be generated with pnpm migrate:generate. Do not hand-write schema migration SQL files; use a generated migration and then edit only when a custom data backfill or other non-schema operation is needed.

Optional flags:

  • --name <name>: Custom migration name
  • --custom: Create empty migration for custom SQL

Applying migrations

# Development/Production
pnpm migrate

# Test database
pnpm migrate:test

Important

Migrations run automatically with pnpm dev and pnpm prod. Never edit migrations after they've been applied to production. Do not rename or reorder generated migration directories after they have been applied.

Environment variables

Do not maintain a second environment-variable inventory in this file. The English and localized install/env.mdx files under docs/src/content/docs/ are the operator-facing source of truth for supported variables, defaults, and storage examples. Read the relevant source module as well when changing behavior.

Adding new environment variables

When adding a new environment variable to Hollo, update these locations:

  1. Source code: Add the environment variable reading logic in the appropriate source file.

  2. Documentation site: Update the English install/env.mdx guide and every localized counterpart present under docs/src/content/docs/.

  3. .env.sample: Add the variable when operators are expected to configure it in a typical installation.

  4. Docker Compose files: If the variable is relevant for Docker deployments:

    • compose.yaml: For S3 storage configuration
    • compose-fs.yaml: For filesystem storage configuration
  5. Changelog: Document the new variable in CHANGES.md under the current version section.

Important notes

  • Single-user focus: Hollo is designed for single-user instances; multi-user logic is not needed
  • Federation first: Always consider federation compatibility when making changes
  • API compatibility: Mastodon API compatibility is critical for client support
  • AGPL compliance: All contributions must comply with AGPL-3.0

When implementing features, always:

  • Test federation with other ActivityPub implementations
  • Verify Mastodon API compatibility with existing clients
  • Add appropriate database indexes for new queries
  • Include tests for new functionality

Markdown style guide

When creating or editing Markdown documentation files in this project, follow these style conventions to maintain consistency with existing documentation:

Headings

  • Setext-style headings: Use underline-style for the document title (with =) and sections (with -):

    Document Title
    ==============
    
    Section Name
    ------------
    
  • ATX-style headings: Use only for subsections within a section:

    ### Subsection Name
    
  • Heading case: Use sentence case (capitalize only the first word and proper nouns) rather than Title Case:

    Development commands    ← Correct
    Development Commands    ← Incorrect
    

Text formatting

  • Italics (*text*): Use for package names (@fedify/fedify, drizzle-orm), file paths, emphasis, and to distinguish concepts
  • Bold (**text**): Use sparingly for strong emphasis
  • Inline code (`code`): Use for code spans, function names, variable names, and command-line options

Lists

  • Use - (space-hyphen-two spaces) for unordered list items

  • Indent nested items with 4 spaces

  • Align continuation text with the item content:

     -  *First item*: Description text that continues
        on the next line with proper alignment
     -  *Second item*: Another item
    

Code blocks

  • Use four tildes (~~~~) for code fences instead of backticks

  • Always specify the language identifier:

    ~~~~ typescript
    const example = "Hello, world!";
    ~~~~
    
  • For shell commands, use bash:

    ~~~~ bash
    pnpm test
    ~~~~
    

Links

  • Use reference-style links placed at the end of each section (not at document end)

  • Format reference links with consistent spacing:

    See the [Fedify documentation] for ActivityPub details.
    
    [Fedify documentation]: https://fedify.dev/
    

GitHub alerts

Use GitHub-style alert blocks for important information:

  • Note: > [!NOTE]
  • Tip: > [!TIP]
  • Important: > [!IMPORTANT]
  • Warning: > [!WARNING]
  • Caution: > [!CAUTION]

Continue alert content on subsequent lines with >:

> [!CAUTION]
> This feature is experimental and may change in future versions.

Tables

Use pipe tables with proper alignment markers:

| Package         | Description                   |
| --------------- | ----------------------------- |
| drizzle-orm     | ORM for PostgreSQL            |

Spacing and line length

  • Wrap lines at approximately 80 characters for readability
  • Use one blank line between sections and major elements
  • Use two blank lines before Setext-style section headings
  • Place one blank line before and after code blocks
  • End sections with reference links (if any) followed by a blank line