Commit graph

204 commits

Author SHA1 Message Date
b9a5bb2afa chore(peregrine): rename compose.menagerie.yml to compose.demo.yml
Public demo instances moving to demo.circuitforge.tech;
menagerie.circuitforge.tech reserved for cloud-hosted managed instances.
2026-03-09 14:55:38 -07:00
ec39c3882e docs: update features table to reflect BYOK tier policy
AI features (cover letter gen, research, interview prep, survey assistant)
are now correctly shown as unlockable at the free tier with any local LLM
or user-supplied API key. Paid tier value prop is managed cloud inference
+ integrations + email sync, not AI feature gating.

Also fixes circuitforge.io → circuitforge.tech throughout.
2026-03-07 22:17:18 -08:00
af0ea560b7 chore: move internal plans to circuitforge-plans repo
All docs/plans/ files migrated to pyr0ball/circuitforge-plans.
Keeping docs/ for future user-facing documentation.
2026-03-07 15:38:47 -08:00
ceac050c49 chore: expand peregrine .gitleaks.toml allowlists for history scan
Suppress false positives found during pre-push history scan:
- Path allowlists: docs/plans/*, tests/*, Streamlit app files,
  SearXNG default config, apple_calendar.py placeholder
- Regex allowlists: Unix epoch timestamps, localhost ports,
  555-area-code variants, CFG-* example license key patterns
- All 164 history commits now scan clean
2026-03-07 13:24:18 -08:00
703b2aec9d chore: activate circuitforge-hooks, add peregrine .gitleaks.toml
- Wire core.hooksPath → circuitforge-hooks/hooks via install.sh
- Add .gitleaks.toml extending shared base config with Peregrine-specific
  allowlists (Craigslist/LinkedIn IDs, localhost port patterns)
- Remove .githooks/pre-commit (superseded by gitleaks hook)
- Update setup.sh activate_git_hooks() to call circuitforge-hooks/install.sh
  with .githooks/ as fallback if hooks repo not present
2026-03-07 13:20:52 -08:00
f2a7a3e881 docs: update changelog for v0.3.0 release
- Add v0.3.0 section: feedback button, BYOK warning, LLM suggest,
  backup/restore, privacy scrub
- Retroactively document v0.2.0 (was in [Unreleased])
- Clear [Unreleased] for future work
2026-03-06 16:04:28 -08:00
3fae4de3ad feat: merge feedback-button branch — BYOK warning, PII scrub, LLM suggest, sidebar indicator
Key changes in this branch:
- BYOK cloud backend detection (scripts/byok_guard.py) with full test coverage
- Sidebar amber badge when any cloud LLM backend is active
- Activation warning + acknowledgment required when enabling cloud backend in Settings
- Privacy policy reference doc added
- Suggest search terms, resume keywords, and LLM suggest button in Settings
- Test suite anonymized: real personal data replaced with fictional Alex Rivera
- Full PII scrub from git history (name, email, phone number)
- Digest email parser design doc
- Settings widget crash fixes, Docker service controls, backup/restore script
2026-03-06 16:01:44 -08:00
ce760200ed test: anonymize real personal data — use fictional Alex Rivera throughout test suite 2026-03-06 15:35:04 -08:00
673e9ed267 fix: remove dead byok_cloud_acknowledged scalar key — list is the authority 2026-03-06 15:17:26 -08:00
f0a5aafd7f docs: clarify byok acknowledgment semantics and double-read intent 2026-03-06 15:14:26 -08:00
fc2605da43 feat: byok activation warning — require acknowledgment when enabling cloud LLM 2026-03-06 15:09:43 -08:00
293df60a00 fix: use explicit utf-8 encoding when reading llm.yaml in sidebar 2026-03-06 14:52:22 -08:00
228912f112 feat: sidebar cloud LLM indicator — amber badge when any cloud backend active 2026-03-06 14:48:20 -08:00
f60ac07541 test: add missing base_url edge case + clarify 0.0.0.0 marker intent
Document defensive behavior: openai_compat with no base_url returns True
(cloud) because unknown destination is assumed cloud. Add explanatory
comment to LOCAL_URL_MARKERS for the 0.0.0.0 bind-address case.
2026-03-06 14:43:45 -08:00
47d8317d56 feat: byok_guard — cloud backend detection with full test coverage 2026-03-06 14:40:06 -08:00
3687f5fc5e docs: add privacy policy reference 2026-03-05 20:59:01 -08:00
e7560f55af feat: add LLM suggest button to Skills & Keywords section
Places a  Suggest button inline with the Skills & Keywords subheader.
On click, calls suggest_resume_keywords() and stores results in session
state. Suggestions render as per-category chip panels (skills, domains,
keywords); clicking a chip appends it to the YAML and removes it from
the panel. A ✕ Clear button dismisses the panel entirely.
2026-03-05 15:13:57 -08:00
dcf2c6af34 feat: wire enhanced suggest_search_terms into Search tab (three-angle excludes)
- Remove old inline _suggest_search_terms (no blocklist/profile awareness)
- Replace with import shim delegating to scripts/suggest_helpers.py
- Call site now loads blocklist.yaml + user.yaml and passes them through
- Update button help text to reflect blocklist, mission values, career background
2026-03-05 15:08:07 -08:00
ce8d5a4ac0 feat: add suggest_resume_keywords for skills/domains/keywords gap analysis
Replaces NotImplementedError stub with full LLM-backed implementation.
Builds a prompt from the last 3 resume positions plus already-selected
skills/domains/keywords, calls LLMRouter, and returns de-duped suggestions
in all three categories.
2026-03-05 15:00:53 -08:00
4e600c3019 fix: guard mission_preferences values against non-string types in suggest_search_terms 2026-03-05 13:40:53 -08:00
b841ac5418 feat: add suggest_search_terms with three-angle exclude analysis
Replaces NotImplementedError stub with a real LLMRouter-backed implementation
that builds a structured prompt covering blocklist alias expansion, values
misalignment, and role-type filtering, then parses the JSON response into
suggested_titles and suggested_excludes lists.

Moves LLMRouter import to module level so tests can patch it at
scripts.suggest_helpers.LLMRouter.
2026-03-05 13:15:25 -08:00
60f067dd0d fix: Settings widget crash, stale setup banners, Docker service controls
- Settings → Search: add-title (+) and Import buttons crashed with
  StreamlitAPIException when writing to _sp_titles_multi after it was
  already instantiated. Fix: pending-key pattern (_sp_titles_pending /
  _sp_locs_pending) applied before widget renders on next pass.

- Home setup banners: fired for email/notion/keywords even when those
  features were already configured. Add 'done' condition callables
  (_email_configured, _notion_configured, _keywords_configured) to
  suppress banners automatically when config files are present.

- Services tab start/stop buttons: docker CLI was unavailable inside
  the container so _docker_available was False and buttons never showed.
  Bind-mount host /usr/bin/docker (ro) + /var/run/docker.sock into the
  app container so it can control sibling containers via DooD pattern.
2026-03-04 12:11:23 -08:00
40d87dc014 fix: DEFAULT_DB respects STAGING_DB env var — was ignoring Docker-set path 2026-03-04 11:47:59 -08:00
d56c44224f feat: backup/restore script with multi-instance and legacy support
- create_backup() / restore_backup() / list_backup_contents() public API
- --base-dir PATH flag: targets any instance root (default: this repo)
  --base-dir /devl/job-seeker backs up the legacy Conda install
- _DB_CANDIDATES fallback: data/staging.db (Peregrine) or staging.db root (legacy)
- Manifest records source label (dir name), source_path, created_at, files, includes_db
- Added config/resume_keywords.yaml and config/server.yaml to backup lists
- 21 tests covering create, list, restore, legacy DB path, overwrite, roundtrip
2026-03-04 10:52:51 -08:00
1c7980cc78 fix: save form data to non-widget state on Next, fix disabled timing, pass page title 2026-03-03 15:17:45 -08:00
042bb519de fix: llm_backend reads fallback_order, logs tee'd to data/.streamlit.log in Docker 2026-03-03 15:04:18 -08:00
606cc0fa4d feat: paste/drag-drop image component, remove server-side Playwright capture button 2026-03-03 14:40:47 -08:00
4aa9f7f91a fix: remove st.rerun() from dialog nav buttons — caused dialog to close on Next/Back 2026-03-03 13:28:26 -08:00
c394ef792a fix: pass FORGEJO env vars into app container 2026-03-03 13:17:37 -08:00
582f2422ff fix: lazy-import playwright in screenshot_page, fix SQLite connection leak in collect_listings 2026-03-03 12:45:39 -08:00
cf85d9d80d feat: wire feedback button into app.py sidebar 2026-03-03 12:38:53 -08:00
06fe5ae42b feat: floating feedback button + two-step dialog (Streamlit shell) 2026-03-03 12:20:27 -08:00
260be9e821 feat: feedback_api — screenshot_page with Playwright (graceful fallback) 2026-03-03 12:14:33 -08:00
b77bb754af feat: feedback_api — Forgejo label management + issue filing + attachment upload 2026-03-03 12:09:11 -08:00
1940cfb131 feat: feedback_api — build_issue_body 2026-03-03 12:00:01 -08:00
6764ad4288 feat: feedback_api — collect_logs + collect_listings 2026-03-03 11:56:35 -08:00
faf65023b4 chore: remove unused imports from feedback_api (will be re-added in later tasks) 2026-03-03 11:45:14 -08:00
7f46d7fadf feat: feedback_api — mask_pii + collect_context 2026-03-03 11:43:35 -08:00
a668745e8b chore: add playwright dep and Forgejo env config for feedback button 2026-03-03 11:38:14 -08:00
9d160093e8 ci: add GitHub Actions pytest workflow 2026-03-02 20:44:33 -08:00
5a6b2908e9 docs: add canonical-source banner and CI badge to README 2026-03-02 20:44:23 -08:00
1bd9671cf5 feat: issue templates, PR template, security redirect 2026-03-02 19:35:06 -08:00
b590c875ed docs: add CONTRIBUTING.md with BSL policy and CLA note 2026-03-02 19:26:25 -08:00
354ca0b24c docs: add SECURITY.md — responsible disclosure policy 2026-03-02 19:26:23 -08:00
108ce6210a feat: setup.sh activates .githooks on clone 2026-03-02 19:17:05 -08:00
b78c084152 feat: commit-msg hook enforces conventional commit format 2026-03-02 19:14:31 -08:00
7c87a7e6cf feat: pre-commit hook blocks sensitive files and key patterns 2026-03-02 19:12:14 -08:00
f1194cacc9 docs: update tier-system reference with BYOK policy + demo user.yaml
docs/reference/tier-system.md:
  - Rewritten tier table: free tier now described as "AI unlocks with BYOK"
  - New BYOK section explaining the policy and rationale
  - Feature gate table gains BYOK-unlocks? column
  - API reference updated: can_use, tier_label, has_configured_llm with examples
  - "Adding a new feature gate" guide updated to cover BYOK_UNLOCKABLE

demo/config/user.yaml:
  - Reformatted by YAML linter; added dismissed_banners for demo UX
2026-03-02 13:22:10 -08:00
ebb82b7ca7 feat: BYOK unlocks LLM features regardless of tier
BYOK policy: if a user supplies any LLM backend (local ollama/vllm or
their own API key), they get full access to AI generation features.
Charging for the UI around a service they already pay for is bad UX.

app/wizard/tiers.py:
  - BYOK_UNLOCKABLE frozenset: pure LLM-call features that unlock with
    any configured backend (llm_career_summary, company_research,
    interview_prep, survey_assistant, voice guidelines, etc.)
  - has_configured_llm(): checks llm.yaml for any enabled non-vision
    backend; local + external API keys both count
  - can_use(tier, feature, has_byok=False): BYOK_UNLOCKABLE features
    return True when has_byok=True regardless of tier
  - tier_label(feature, has_byok=False): suppresses lock icon for
    BYOK_UNLOCKABLE features when BYOK is active

Still gated (require CF infrastructure, not just an LLM call):
  llm_keywords_blocklist, email_classifier, model_fine_tuning,
  shared_cover_writer_model, multi_user, all integrations

app/pages/2_Settings.py:
  - Compute _byok = has_configured_llm() once at page load
  - Pass has_byok=_byok to can_use() for _gen_panel_active
  - Update caption to mention BYOK as an alternative to paid tier

app/pages/0_Setup.py:
  - Wizard generation widget passes has_byok=has_configured_llm()
    to can_use() and tier_label()

tests/test_wizard_tiers.py:
  - 6 new BYOK-specific tests covering unlock, non-unlock, and
    label suppression cases
2026-03-02 11:34:36 -08:00
0a728fddbc feat: DEMO_MODE — isolated public menagerie demo instance
Adds a fully neutered public demo for menagerie.circuitforge.tech/peregrine
that shows the Peregrine UI without exposing any personal data or real LLM inference.

scripts/llm_router.py:
  - Block all inference when DEMO_MODE env var is set (1/true/yes)
  - Raises RuntimeError with a user-friendly "public demo" message

app/app.py:
  - IS_DEMO constant from DEMO_MODE env var
  - Wizard gate bypassed in demo mode (demo/config/user.yaml pre-seeds a fake profile)
  - Demo banner in sidebar: explains read-only status + links to circuitforge.tech

compose.menagerie.yml (new):
  - Separate Docker Compose project (peregrine-demo) on host port 8504
  - Mounts demo/config/ and demo/data/ — isolated from personal instance
  - DEMO_MODE=true, no API keys, no /docs mount
  - Project name: peregrine-demo (run alongside personal instance)

demo/config/user.yaml:
  - Generic "Demo User" profile, wizard_complete=true, no real personal info

demo/config/llm.yaml:
  - All backends disabled (belt-and-suspenders alongside DEMO_MODE block)

demo/data/.gitkeep:
  - staging.db is auto-created on first run, gitignored via demo/data/*.db

.gitignore: add demo/data/*.db

Caddy routes menagerie.circuitforge.tech/peregrine* → 8504 (demo instance).
Personal Peregrine remains on 8502, unchanged.
2026-03-02 11:22:38 -08:00