| name | epupp-dev |
| description | Epupp architecture, development patterns, and system contracts. Use when: writing or modifying Epupp source code, implementing features, fixing bugs, debugging extension behavior, working with Uniflow actions or effects, understanding message flows, injection or connection lifecycle, testing strategy, build pipeline, reviewing Epupp PRs, planning implementations, running tests or builds, REPL-driven development, or any coding task in the Epupp workspace. Contains architecture overview, Uniflow contracts, source file map, testing patterns, delegation, and development principles. References hold deep state contracts and temporal sequences. IMPORTANT: Also load when PLANNING Epupp changes, not only at implementation time. |
Epupp Development
Shared knowledge base for developing the Epupp browser extension. Loaded by any agent or mode doing real Epupp work.
Architecture
λ architecture_layers.
editor_or_AI → nREPL_client
→ babashka_relay(browser-nrepl, ports_12345/12346)
→ background_service_worker(chrome.runtime)
→ content_bridge(ISOLATED_world, chrome.runtime ↔ postMessage)
→ ws_bridge(MAIN_world, postMessage ↔ WebSocket)
→ page_context(Scittle_REPL ↔ DOM)
| six_layers | each_boundary ≡ trust_boundary ∧ serialization_point
| ¬direct_editor_to_page | always_relayed
λ build_pipeline.
src/.cljs → squint_compiler → extension/.mjs(ESM) → esbuild → build/.js(IIFE)
| config: squint.edn | bb_squint-compile ≡ compile_check | bb_watch ≡ continuous
| build/.css ∧ build/.html copied_from extension/
| format: IIFE | ¬ESM_in_browser_extension
| define: EXTENSION_CONFIG from config/*.edn
| separate_bundles: background.js popup.js panel.js content-bridge.js ws-bridge.js trigger-scittle.js userscript-loader.js
λ page_runtime.
scittle ≡ SCI_in_browser | true_clojure_keywords
| userscripts_run_in_page_context | full_DOM_access
| async_via ^:async ∧ await | ¬top_level_await
| libraries_injected_via :epupp/inject | bundled_scittle_plugins
λ injection_model.
ensure_scittle! → check_first → inject_only_if_missing
| ensure_bridge! → check_first → inject_only_if_missing
| duplicate_injection → ¬error | ¬duplicate_state
| check_scittle_fn → {hasScittle, hasWsBridge} | both_must_be_true
λ content_bridge_security.
ISOLATED_world: content_bridge.cljs | ¬page_access | chrome.runtime_access
| validates_message_source ∧ type via message_registry
| MAIN_world: ws_bridge.cljs | page_access | ¬chrome.runtime_access
| trust_boundary: ISOLATED ≡ trusted | MAIN ≡ untrusted
Principles
λ epistemology.
assumptions ≡ enemy | benchmark > estimate | measure > guess
| verify_before_stating_fix_locations | mark("needs investigation") when_uncertain
| failure_to_read_docs ≡ #1_cause_of_mistakes
λ data_oriented.
what_would_rich_hickey_do | data > objects | fn > class
| immutable_core > mutable_shell | transform(data) > mutate(state)
| REPL_first: test_functions ∧ explore_data ∧ validate_assumptions_before_coding
| simple > easy | separate(data, behavior) | clear > clever
λ clojure.
definition_order_matters | ¬forward_declares | almost_always ≡ poor_structure
| plan_test_strategy: unit(structural ∧ contracts ∧ invariants) ∧ e2e(integration ∧ real_flows)
| unit ∧ e2e ≡ complementary_tools | ¬sequential_phases
λ api_stability.
user_facing_API ≡ commitment: manifest_keys ∧ epupp.fs ∧ REPL_behaviors
| preserve_existing | break_only_when(cost_compat > cost_users)
| prefer_clean_solutions | ¬contorted_shims | ¬special_case_branching
Uniflow (compact)
λ uniflow_sap.
event_loop ≡ SINGLE_ACCESS_POINT for !state
| actions: pure_fn(state, uf-data, [action & args]) → {:uf/db :uf/fxs :uf/dxs}
| effects: receive(params_from_action) | ¬read(@!state) | ¬transitive_atom_access
| ¬swap! ∧ ¬reset! outside_event_loop
| ref: dev/docs/architecture/uniflow.md
| full_contracts: references/state-contracts.md
λ action_naming.
actions: :domain/ax.verb-noun | effects: :domain/fx.verb-noun
| state: :domain/key-name | messages: "kebab-case-string"
REPLs and Babashka
λ available_repls.
bb → babashka_REPL | scripting ∧ automation
squint → squint_REPL | test_pure_functions_in_Node.js
scittle-dev-repl → scittle_Dev_REPL | test_scittle_code_in_browser_like_env
| develop_solutions_incrementally_in_appropriate_REPL
λ babashka_utilities.
prefer_babashka_builtins > python ∧ shell ∧ external_tools
| http_server: bb_test:server ∨ babashka.http-server | ¬python_-m_http.server
| file_ops: babashka.fs | ¬shell(cp mv rm find)
| process: babashka.process | ¬raw_shell_scripts
| http_client: babashka.http-client | ¬curl | ¬wget
Testing
λ testing_pattern.
unit_tests: vitest | src/test/.cljs → test/.cljs
| test_pure_actions: call_handle-action → assert_return_shape
| test_data_transforms: call_fn → assert_output
| ¬test_effects_in_unit_tests | effects_tested_in_e2e
e2e_tests: playwright_in_docker | e2e/*.cljs
| test_full_flows: injection ∧ connection ∧ eval ∧ userscripts
| bb_test:e2e → docker_build → playwright_run
λ truth_hierarchy.
browser_page > e2e_test > unit_test > source > docs > assumption
| browser_page ≡ ground_truth | where_scittle_actually_runs
| ¬trust(green_tests_alone) → verify_in(real_browser)
λ debug_approach.
1_context: gather(failing_env ⊗ working_env) | what_data_differs
2_trace: data_flow(input → transform → output) | find_divergence_point
3_fix: root_cause(data_flow) | ¬symptom_patch
| six_layer_trace: page_scittle → ws_bridge → content_bridge → background → bb_relay → editor | find_break_point
Delegation
λ subagents.
commit → summary_of_task(bigger_picture) | expert_git_agent
research → context ∧ what_to_know ∧ report_structure
edit → Clojure_editor | files ∧ linenumbers ∧ code ∧ instructions
epupp-elaborator → user_prompt ∧ file_context ∧ session_context → refined_prompt
| delegation ≡ intelligent | protect_context_window ∧ ensure_quality
Documentation
λ docs_by_task.
read_before_starting_work | use(read_file):
| understanding_system → architecture_overview → detailed_docs
| unit_tests → dev/docs/testing-unit.md
| UI(popup/panel) → reagami skill ∧ dev/docs/ui.md
| state/events → dev/docs/architecture/uniflow.md ∧ state-management.md
| messaging → dev/docs/architecture/message-protocol.md
| injection/REPL → dev/docs/architecture/injection-flows.md
| library_deps → dev/docs/architecture/library-namespaces.md
| userscripts → dev/docs/userscripts-architecture.md
| build/release → dev/docs/dev.md
| finding_source → dev/docs/architecture/components.md
| return_to_index_when_scope_changes
λ docs_reference.
consult_when_relevant:
| README.md → user_facing_overview
| dev/docs/architecture/security.md → trust_boundaries ∧ CSP
| dev/docs/architecture/build-pipeline.md → build_config_injection
λ docs_sync.
epupp_repo ≡ source_of_truth | synced_files ≡ generated_artifacts
| README.md → my-epupp-hq/docs/epupp-README.md
| docs/repl-fs-sync.md → my-epupp-hq/docs/repl-fs-sync.md
| docs/connecting-to-epupp.md → my-epupp-hq/docs/connecting-to-epupp.md
| ¬edit(synced_copies) | treat_as_generated
| ∀doc_updates: edit_here(epupp/) | human_runs(bb_docs-sync)_when_ready
Source File Map
λ source_file_map.
src/background.cljs → service_worker | message_routing ∧ init
src/popup.cljs → popup_ui | connection_controls ∧ script_list
src/panel.cljs → devtools_panel | code_editor ∧ eval
src/content_bridge.cljs → ISOLATED_world | message_validation ∧ relay
src/ws_bridge.cljs → MAIN_world | WebSocket_relay ∧ page_comms
src/trigger_scittle.cljs → page_injection | Scittle_loader
src/userscript_loader.cljs → content_script | auto_injection
src/event_handler.cljs → uniflow_engine | dispatch ∧ execute
src/storage.cljs → chrome.storage_mirror | persist ∧ load
src/config.cljs → build_config | dev/prod/test
src/manifest_parser.cljs → EDN_manifest_parsing
src/script_utils.cljs → script_normalization ∧ ID_generation ∧ library_classification
src/scittle_libs.cljs → library_collection ∧ injection
src/bg_ws.cljs → background_WebSocket_management
src/bg_inject.cljs → content_script_injection
src/dep_resolver.cljs → dependency_resolution | pure_resolver ∧ cycle_detection ∧ ext-dep_classification
src/ext_dep.cljs → ext_dep_URL_validation ∧ async_fetch_cache
src/bg_fs_dispatch.cljs → FS_message_routing ∧ optional_:uf/dxs_dispatch
src/popup_actions.cljs → popup_uniflow_actions
src/panel_actions.cljs → panel_uniflow_actions
src/reagami.cljs → minimal_UI_rendering_library
src/background_actions.cljs → background_uniflow_actions | re-resolution
src/background_actions/*.cljs → background_action_modules
Deep References
Load as needed per task: