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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 10 additions & 69 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,75 +1,16 @@
# html2rss-web AI Agent Instructions

## Overview
This repository uses a centralized documentation structure. All AI agents (including Copilot, Gemini CLI, etc.) must follow the constraints and rules defined in the following files:

- Ruby web app that converts websites into RSS 2.0 feeds.
- Built with **Roda** backend + **Preact** frontend, using the **html2rss** gem (+ `html2rss-configs`).
- **Frontend:** Vite-built Preact UI, served alongside Ruby backend.
## Canonical Documentation

## Documentation website of core dependencies
- **Agent Constraints**: [AGENTS.md](../../AGENTS.md) (Execution rules, verification, and UI principles)
- **Contributor Guide**: [docs/README.md](../../docs/README.md) (Architecture, security, setup, and coding style)
- **Design System**: [docs/design-system.md](../../docs/design-system.md) (Visual and CSS rules)

Search these pages before using them. Find examples, plugins, UI components, and configuration options.
## Quick Reference for Agents

### Roda

1. https://roda.jeremyevans.net/documentation.html

### Preact & Vite

1. https://preactjs.com/guide/v10/getting-started/
2. https://vite.dev/guide/

### html2rss

1. If available, find source locally in: `../html2rss`.
2. source code on github: https://github.com/html2rss/html2rss

### Test and Linters

1. https://docs.rubocop.org/rubocop/cops.html
2. https://docs.rubocop.org/rubocop-rspec/cops_rspec.html
3. https://rspec.info/features/3-13/rspec-expectations/built-in-matchers/
4. https://www.betterspecs.org/

Fix rubocop `RSpec/MultipleExpectations` adding rspec tag `:aggregate_failures`.

## Core Rules

- ✅ Organise Roda routes via dedicated modules (e.g. `Html2rss::Web::Routes::*`), keeping the main app class thin.
- ✅ Keep helper modules minimal: define entrypoints with `class << self` and push implementation helpers under `private`; avoid `module_function` unless mirroring existing conventions.
- ✅ Validate all inputs. Pass outbound requests through **SSRF filter**.
- ✅ Add caching headers where appropriate (`Rack::Cache`).
- ✅ Errors: friendly messages for users, detailed logging internally.
- ✅ **Frontend**: Use Preact components in `frontend/src/`. Keep it simple.
- ✅ **CSS**: Use the app-owned frontend styles in `frontend/src/styles/`.
- ✅ **Specs**: RSpec for Ruby, build tests for frontend.
- ✅ When a spec needs to tweak environment variables, wrap the example in `ClimateControl.modify` so state is restored automatically.

## Don't

- ❌ Don't use Ruby's URI class or addressable gem directly. Strictly use `Html2rss::Url` only.
- ❌ Don't bypass SSRF filter or weaken CSP.
- ❌ Don't add databases, ORMs, or background jobs.
- ❌ Don't leak stack traces or secrets in responses.
- ❌ Don't reach into private API with `send(...)`; expose what you need at the module level instead.
- ❌ Don't modify `frontend/dist/` - it's generated by build process.
- ❌ NEVER expose the auth token a user provides.

## Environment

- `RACK_ENV` – environment
- `AUTO_SOURCE_ENABLED`, `AUTO_SOURCE_USERNAME`, `AUTO_SOURCE_PASSWORD`, `AUTO_SOURCE_ALLOWED_ORIGINS`
- `HEALTH_CHECK_USERNAME`, `HEALTH_CHECK_PASSWORD`
- `SENTRY_DSN` (optional)

### Verification Steps

- Run `ruby -c app.rb` to check syntax
- Run `bundle exec rspec` to verify tests
- Check `bundle install` removes unused dependencies

## Style

- Add `# frozen_string_literal: true`
- Follow RuboCop style
- YARD doc comments for public methods
- **Environment**: All commands MUST run inside the Dev Container.
- **Verification**: Run `make ready` before any commit.
- **Security**: Follow strict [Security & Safety Rules](../../docs/README.md#security--safety-rules).
- **Style**: Follow [Architectural Constraints](../../docs/README.md#architectural-constraints) (YARD docs, Roda organization).
101 changes: 34 additions & 67 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,84 +1,51 @@
# Agent Workflow (Dev Container)
# Agent Workflow Constraints

## Start the Dev Container

```text
docker compose -f .devcontainer/docker-compose.yml up -d
```

## Commands (run inside the container)

```text
docker compose -f .devcontainer/docker-compose.yml exec -T app make setup

docker compose -f .devcontainer/docker-compose.yml exec -T app make dev

docker compose -f .devcontainer/docker-compose.yml exec -T app make test

docker compose -f .devcontainer/docker-compose.yml exec -T app make ready

docker compose -f .devcontainer/docker-compose.yml exec -T app bundle exec rubocop -F

docker compose -f .devcontainer/docker-compose.yml exec -T app bundle exec rspec
```

Pre-commit gate (required):

```text
docker compose -f .devcontainer/docker-compose.yml exec -T app make ready
```

If you need an interactive shell:

```text
docker compose -f .devcontainer/docker-compose.yml exec app bash
```

---
This document defines execution constraints for AI agents. For general contributor rules, setup commands, architectural constraints, and security policies, see [docs/README.md](docs/README.md).

## Collaboration Agreement (Agent ↔ User)

## Interview Answers (ID-able) + Expert Recommendations

**DoD:** `make ready` in Dev Container; if applicable, user completes manual smoke test with agent-provided steps.
**Verification:** Always smoke Dev Container + `make ready`.
**Commits:** Group by logical unit after smoke-tested (feature / improvement / refactor).
**Responses:** Changes → Commands → Results → Next steps, ending with a concise one-line summary.
**KISS vs Refactor:** KISS by default; boy-scout refactors allowed if low-risk and simplifying.
**Ambiguity:** Proceed with safest assumption, then confirm.
**Non-negotiables:** Dev Container only; security first.

Expert recommendation: keep workflows terminal-first and keyboard-focused (clear commands, no GUI-only steps).
- **DoD:** `make ready` in Dev Container; if applicable, user completes manual smoke test with agent-provided steps.
- **Verification:** Always smoke Dev Container + `make ready`.
- **Commits:** Group by logical unit after smoke-tested (feature / improvement / refactor).
- **Responses:** Changes → Commands → Results → Next steps, ending with a concise one-line summary.
- **KISS vs Refactor:** KISS by default; boy-scout refactors allowed if low-risk and simplifying.
- **Ambiguity:** Proceed with safest assumption, then confirm.
- **Non-negotiables:** Dev Container only; security first.

## Definition of Done

- Run `make ready` inside the Dev Container.
- If applicable, user completes manual smoke test; agent provides clear instructions.

## Verification Rules
## Agent-Specific Verification Rules

- Always run Dev Container smoke + `make ready` for changes.
- For frontend changes, also verify in `chrome-devtools` MCP at `http://127.0.0.1:4001/` while the Dev Container is running.
- Capture a quick state check for all affected UI states (e.g., guest/member/result) to enforce state parity and avoid duplicate actions.

## Commit Granularity
### Frontend Smoke Checklist

- Group commits by logical units after they have grown and been smoke-tested (feature / improvement / refactor).
- Start the Dev Container and app (`make dev`).
- Open `http://127.0.0.1:4001/` with `chrome-devtools` MCP.
- Validate the primary user path touched by the change.
- Verify all affected states (e.g., guest/member/result) keep the same layout grammar.
- Confirm action uniqueness: one canonical control per outcome in each state.

## Response Format
## UI Execution Principles

- Default: Changes → Commands → Results → Next steps.
- End with a concise one-line summary.
See [docs/design-system.md](docs/design-system.md) for visual rules.

## KISS vs Refactor
- **Task Dominance:** Each UI state should make one user objective obvious and primary. Supporting surfaces and links must yield priority.
- **Copy Minimalism:** Remove text that repeats what the interface already communicates. Prefer action-oriented wording.
- **State Skeleton:** Adjacent UI states should read as the same frame with content changes, not as separate pages.
- **Focus Contract:** Verify browser autofocus and return-focus behavior on initial load and after transitions.
- **Support Compression:** When a user has advanced past setup, reduce the visual weight of support content.

- KISS by default.
- Boy-scout refactors are allowed when they reduce complexity and are low-risk.

## Ambiguity Handling
## Response Format

- Proceed with the safest assumption, then confirm.
1. **Changes:** Briefly list files/symbols modified.
2. **Commands:** Show the verification commands run.
3. **Results:** Summarize the outcome.
4. **Next steps:** Propose the immediate follow-up.
5. **One-line Summary:** End with a concise summary.

## Non-Negotiables

- Security first.
- YARD docs are strict for public Ruby methods in `app/`: every public method must have a YARD docstring with typed `@param` tags (for all params) and typed `@return`.
- When touching non-public methods, add YARD docs when it improves maintenance or clarifies invariants/edge handling.
- **Security first:** No leaking secrets or insecure patterns. See [Security & Safety Rules](docs/README.md#security--safety-rules).
- **YARD docs:** Strict for public Ruby methods in `app/`. Every public method must have a YARD docstring with typed `@param` and `@return`. See [Architectural Constraints](docs/README.md#architectural-constraints).
- **No host execution:** All commands MUST run inside the Dev Container via `make` or `bundle exec`.
1 change: 0 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ gem 'parallel'
gem 'rack-cache'
gem 'rack-timeout'
gem 'roda'
gem 'ssrf_filter'
gem 'zeitwerk'

gem 'puma', require: false
Expand Down
23 changes: 10 additions & 13 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
GIT
remote: https://github.com/html2rss/html2rss
revision: e0dca5bf74b17c1e2a0618fc0a4af27c16da1883
revision: 7672db3109769b059110d8b7bea55cf68ba36a39
branch: master
specs:
html2rss (0.17.0)
Expand Down Expand Up @@ -65,7 +65,7 @@ GEM
addressable (2.8.9)
public_suffix (>= 2.0.2, < 8.0)
ast (2.4.3)
async (2.38.0)
async (2.38.1)
console (~> 1.29)
fiber-annotation
io-event (~> 1.11)
Expand Down Expand Up @@ -167,7 +167,7 @@ GEM
io-endpoint (0.17.2)
io-event (1.14.4)
io-stream (0.11.1)
json (2.19.1)
json (2.19.2)
json-schema (6.2.0)
addressable (~> 2.8)
bigdecimal (>= 3.1, < 5)
Expand All @@ -185,7 +185,7 @@ GEM
mime-types (3.7.0)
logger
mime-types-data (~> 3.2025, >= 3.2025.0507)
mime-types-data (3.2026.0303)
mime-types-data (3.2026.0317)
minitest (6.0.2)
drb (~> 2.0)
prism (~> 1.5)
Expand Down Expand Up @@ -220,7 +220,7 @@ GEM
protocol-http2 (0.24.0)
protocol-hpack (~> 1.4)
protocol-http (~> 0.47)
protocol-rack (0.21.1)
protocol-rack (0.22.0)
io-stream (>= 0.10)
protocol-http (~> 0.58)
rack (>= 1.0)
Expand Down Expand Up @@ -333,7 +333,6 @@ GEM
simplecov_json_formatter (~> 0.1)
simplecov-html (0.13.2)
simplecov_json_formatter (0.1.4)
ssrf_filter (1.3.0)
stackprof (0.2.28)
thor (1.5.0)
traces (0.18.2)
Expand Down Expand Up @@ -386,7 +385,6 @@ DEPENDENCIES
ruby-lsp
sentry-ruby
simplecov
ssrf_filter
stackprof
vcr
webmock
Expand All @@ -399,7 +397,7 @@ CHECKSUMS
activesupport (8.1.2) sha256=88842578ccd0d40f658289b0e8c842acfe9af751afee2e0744a7873f50b6fdae
addressable (2.8.9) sha256=cc154fcbe689711808a43601dee7b980238ce54368d23e127421753e46895485
ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
async (2.38.0) sha256=f95d00da2eb72e2c5340a6d78c321ec70cec65cbeceb0dc2cb2a32ff17a0f4cf
async (2.38.1) sha256=72ba6b7de04d852355458bfe891221226bb7d29f055f5cb043ae3345497f8cec
async-http (0.94.2) sha256=c5ca94b337976578904a373833abe5b8dfb466a2946af75c4ae38c409c5c78b2
async-pool (0.11.2) sha256=0a43a17b02b04d9c451b7d12fafa9a50e55dc6dd00d4369aca00433f16a7e3ed
async-websocket (0.30.0) sha256=55739954528ad8f87f7792d0452e1268d1ef2aa5b3719f79400a05a1a6202cdf
Expand Down Expand Up @@ -441,7 +439,7 @@ CHECKSUMS
io-endpoint (0.17.2) sha256=3feaf766c116b35839c11fac68b6aaadc47887bb488902a57bf8e1d288fb3338
io-event (1.14.4) sha256=455a9e4fb4613d12867b90461c297af6993b400a521bf62046f83b27f9c6aa3d
io-stream (0.11.1) sha256=fa5f551fcff99581c1757b9d1cee2c37b124f07d2ca4f40b756a05ab9bd21b87
json (2.19.1) sha256=dd94fdc59e48bff85913829a32350b3148156bc4fd2a95a2568a78b11344082d
json (2.19.2) sha256=e7e1bd318b2c37c4ceee2444841c86539bc462e81f40d134cf97826cb14e83cf
json-schema (6.2.0) sha256=e8bff46ed845a22c1ab2bd0d7eccf831c01fe23bb3920caa4c74db4306813666
kramdown (2.5.2) sha256=1ba542204c66b6f9111ff00dcc26075b95b220b07f2905d8261740c82f7f02fa
language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
Expand All @@ -451,7 +449,7 @@ CHECKSUMS
mcp (0.8.0) sha256=ae8bd146bb8e168852866fd26f805f52744f6326afb3211e073f78a95e0c34fb
metrics (0.15.0) sha256=61ded5bac95118e995b1bc9ed4a5f19bc9814928a312a85b200abbdac9039072
mime-types (3.7.0) sha256=dcebf61c246f08e15a4de34e386ebe8233791e868564a470c3fe77c00eed5e56
mime-types-data (3.2026.0303) sha256=164af1de5824c5195d4b503b0a62062383b65c08671c792412450cd22d3bc224
mime-types-data (3.2026.0317) sha256=77f078a4d8631d52b842ba77099734b06eddb7ad339d792e746d2272b67e511b
minitest (6.0.2) sha256=db6e57956f6ecc6134683b4c87467d6dd792323c7f0eea7b93f66bd284adbc3d
net-http (0.9.1) sha256=25ba0b67c63e89df626ed8fac771d0ad24ad151a858af2cc8e6a716ca4336996
nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1
Expand All @@ -470,7 +468,7 @@ CHECKSUMS
protocol-http (0.60.0) sha256=ca1354947676d663b6f23c49654aee464288774e7867c4a6e406fecce9691cec
protocol-http1 (0.37.0) sha256=5bdd739e28792b341134596f6f5ab21a9d4b395f67bae69e153743eb0e69d123
protocol-http2 (0.24.0) sha256=65327a019b7e36d2774e94050bf57a43bb60212775d2fcf02ae1d2ed4f01ef28
protocol-rack (0.21.1) sha256=366ff16efbf4c2f8d2e3fad4e992effa2357610f70effbccfa2767d26fedc577
protocol-rack (0.22.0) sha256=b7c49c0b597ca2c6d20f8bcd746c4415a1b750eacfbe64f828e780c978a4293d
protocol-url (0.4.0) sha256=64d4c03b6b51ad815ac6fdaf77a1d91e5baf9220d26becb846c5459dacdea9e1
protocol-websocket (0.20.2) sha256=c41d93c35fba5dae85375c597f76975f3dbd75d8c5b2f21b33dab4dc22a5a511
public_suffix (7.0.5) sha256=1a8bb08f1bbea19228d3bed6e5ed908d1cb4f7c2726d18bd9cadf60bc676f623
Expand Down Expand Up @@ -513,7 +511,6 @@ CHECKSUMS
simplecov (0.22.0) sha256=fe2622c7834ff23b98066bb0a854284b2729a569ac659f82621fc22ef36213a5
simplecov-html (0.13.2) sha256=bd0b8e54e7c2d7685927e8d6286466359b6f16b18cb0df47b508e8d73c777246
simplecov_json_formatter (0.1.4) sha256=529418fbe8de1713ac2b2d612aa3daa56d316975d307244399fa4838c601b428
ssrf_filter (1.3.0) sha256=66882d7de7d09c019098d6d7372412950ae184ebbc7c51478002058307aba6f2
stackprof (0.2.28) sha256=4ec2ace02f386012b40ca20ef80c030ad711831f59511da12e83b34efb0f9a04
thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73
traces (0.18.2) sha256=80f1649cb4daace1d7174b81f3b3b7427af0b93047759ba349960cb8f315e214
Expand All @@ -530,4 +527,4 @@ CHECKSUMS
zlib (3.2.3) sha256=5bd316698b32f31a64ab910a8b6c282442ca1626a81bbd6a1674e8522e319c20

BUNDLED WITH
4.0.8
4.0.6
Loading
Loading