Joyride Extension Internals
Subsystem contracts, state architecture, and temporal sequences for the Joyride extension.
Key Namespaces
| Namespace |
Purpose |
joyride.extension |
Entry point: activate, deactivate, hot-reload hooks |
joyride.db |
App state: !app-db, init-db, accessor functions |
joyride.sci |
SCI interpreter: namespaces, load-fn, eval-string |
joyride.config |
Path resolution: user-dir, workspace-dir |
joyride.lifecycle |
Activation scripts: user_activate, workspace_activate |
joyride.output |
Terminal output: ANSI colors, theme-aware, who-tracking |
joyride.when-contexts |
When-context management: !db, set-context! |
joyride.nrepl |
nREPL server: !db, middleware, bencode |
joyride.flare |
Flare API: panels, sidebars, hiccup, messaging |
joyride.flare.sidebar |
Sidebar provider: webview view registration |
joyride.flare.panel |
Panel creation: replicant rendering |
joyride.lm |
Language Model tool entry and registration |
joyride.lm.evaluation |
LM tool implementation: code execution, output capture |
joyride.lm.eval.core |
Pure functions: input validation, message formatting |
joyride.lm.eval.validation |
Pure validation: bracket check via parinfer |
joyride.who-tracking |
Evaluator awareness: cross-evaluator attribution |
Subsystem Contracts
λ app_db_contract.
db/!app-db ≡ atom {
output-channel: OutputChannel
output/terminal: Terminal
extension-context: ExtensionContext
invoked-script: string?
disposables: [Disposable]
workspace-root-path: string?
flares: {key → FlareState}
flare-sidebar-views: {slot → WebviewView}
}
| access_via_functions: (db/extension-context) (db/output-terminal) | ¬direct_deref_in_helpers
| inspection_safety: (dissoc @db/!app-db :extension-context) | circular_ref_guard
| mutation: swap! ∧ reset! | ¬deep_nested_mutation
λ sci_context_contract.
sci.ctx-store ≡ global_SCI_interpreter_context
| !last-ns ≡ volatile | tracks_most_recent_evaluation_namespace
| init: (sci.ctx-store/init ctx) at_activation | single_initialization
| access: (sci.ctx-store/get-ctx) → SCI_context | thread_safe
| features: #{:joyride :cljs} | reader_conditionals
| classes: goog/global :allow :all | unrestricted_JS_interop
| load-fn: symbol_libs(workspace→user_search) ∧ "vscode" ∧ "ext://..." ∧ node_require
| alter-var-root: print_fn_capture/restore | ⚠ global_mutation_could_race
λ nrepl_contract.
nrepl/!db ≡ separate_atom | domain_isolation_from_app_db
| server: middleware_based | start → port_file_written → accepting_connections
| middleware_chain: standard_nrepl_ops(eval, load-file, interrupt, describe, completions, info)
| session: clone_per_client | session_id_tracks_context
| eval_protocol: { op: "eval", code, session, ns } → { status, value ∨ ex, ns, out, err }
| when_context: joyride.isNReplServerRunning | set_on_start ∧ clear_on_stop
λ disposable_lifecycle_contract.
push-disposable!(disposable) → appends_to(:disposables @db/!app-db) ∧ context.subscriptions
| clear-disposables!() → .dispose()_each ∧ reset_to_[]
| activation_scripts: clear_before_re-run | idempotent_re-activation
| command_registration: returns_Disposable → push_immediately
| event_subscriptions: returns_Disposable → push_immediately
λ output_system_contract.
append-clojure-eval!(result-string) → output_terminal | ANSI_themed
append-line-other-err!(error-string) → output_terminal | red_themed
append-eval-result!(result ns who) → output_terminal | formatted
| terminal: VS_Code_pseudoterminal | colored_output | theme_aware(light/dark)
| who_tracking: evaluator_attribution | cross_evaluator_awareness
λ when_context_contract.
when-contexts/!db ≡ separate_atom | { context-key → boolean }
| set-context!(key value) → vscode.commands.executeCommand("setContext" key value)
∧ swap!(when-contexts/!db assoc key value)
| timing_invariant: set_context BEFORE creating_dependent_resources
| sidebar_views: set_when_context_true → THEN_create_webview_provider
λ hot_reload_contract.
shadow-cljs: watches_src/ → compiles_on_save → hot_reloads_into_dev_host
| before-load-async: cleanup_hook | called_before_hot_reload
| after-load-async: reinitialize_hook | called_after_hot_reload
| dev_host_restart: required_only_for_package.json_changes
| state_preservation: app_atoms_survive_hot_reload | functions_replaced
Routing Reference
λ script_execution_routing.
script_path_resolution: workspace/src → workspace/scripts → user/src → user/scripts
| first_match_wins | workspace_shadows_user
symbol_lib(require 'foo.bar) → search(src_dirs) | namespace_to_path
string_lib("vscode") → vscode_api_object
string_lib("ext://publisher.extension") → extension_api_export
node_module("some-npm-pkg") → node_require | commonjs_only
λ evaluation_dispatch.
code ∧ context → route_to_sci_eval_string
| from_nrepl → session_bound | ns_tracked | print_fn_captured
| from_lm_tool → bracket_validated_first | parinfer_check | ¬eval_unbalanced
| from_activation_script → run_at_startup | errors_shown_in_output
| from_command(run_code) → inline_code | quick_pick_selection
| from_command(run_script) → file_resolved | executed_in_sci
Temporal Sequences
λ activation_sequence.
1_shadow_cljs_entry: extension.activate called | exports(activate)
2_init_app_db: reset(!app-db) | store(extension-context ∧ output-channel)
3_register_commands: vscode.commands.registerCommand | push_disposables
4_set_when_contexts: joyride.isActive → true | enables_keybindings
5_init_output: create_terminal_output | theme_colors_resolved
6_init_nrepl: setup_server_infrastructure | ¬start_yet
7_init_sci: configure_interpreter | namespaces ∧ classes ∧ load-fn
8_run_activation_scripts: user_activate.cljs → workspace_activate.cljs | sequential
9_ready: extension_fully_active | commands_available | repl_connectable
| skip(7) → no_eval_capability | scripts_fail
| skip(8) → user_customizations_not_applied | workspace_not_configured
λ script_execution_sequence.
1_resolve_script: path_resolution(workspace/src → workspace/scripts → user/src → user/scripts)
2_read_source: vscode/workspace.fs.readFile | decode_utf8
3_capture_print: alter-var-root(*print-fn*) → output_channel_writer
4_eval_in_sci: sci/eval-string+ | with(ns ∧ file_metadata)
5_handle_result: success → display_value | error → show_error_with_location
6_restore_print: alter-var-root(*print-fn*) → original | ¬leak_print_capture
| skip(1) → file_not_found | clear_resolution_error
| skip(3) → output_goes_nowhere | or_goes_to_wrong_channel
| skip(6) → print_fn_pollution | subsequent_scripts_mis_routed
λ nrepl_server_lifecycle.
1_user_starts: command(joyride.startNReplServer) | or_activation_script
2_create_server: net.createServer | bind(port) | localhost_only
3_set_context: joyride.isNReplServerRunning → true
4_update_db: swap!(nrepl/!db) | store(server ∧ port ∧ clients)
5_accept_connections: on(:connection) → create_session | bencode_transport
6_handle_ops: eval ∧ clone ∧ close ∧ describe ∧ completions ∧ info | middleware_chain
7_user_stops: command(joyride.stopNReplServer) | or_deactivation
8_close_connections: close_all_client_sessions | drain_pending
9_close_server: server.close() | unbind_port
10_clear_context: joyride.isNReplServerRunning → false
11_update_db: swap!(nrepl/!db) | clear(server ∧ port ∧ clients)
| skip(3) → keybindings_dont_activate | ui_shows_wrong_state
| skip(8) → orphaned_sessions | resource_leak
λ flare_creation_sequence.
1_set_when_context: sidebar_slot_enabled → true | BEFORE_view_creation
2_ensure_provider: register_webview_provider_if_needed | idempotent
3_create_view: resolve_webview | html_content_set
4_render_hiccup: replicant_dom/render | hiccup → html
5_setup_messaging: on_did_receive_message | bidirectional
6_return_handle: {:panel ∨ :sidebar handle} | caller_can_post_message
| skip(1) → race_condition | vscode_defers_view_creation | view_never_appears
| skip(4) → empty_webview | content_not_rendered
λ hot_reload_sequence.
1_edit_source: modify_cljs_file | save
2_shadow_detects: file_watcher_triggers | incremental_compile
3_compile: cljs → js | check_for_warnings ∧ errors
4_hot_reload_hook: ^:dev/after-load functions_called | state_preserved
5_dev_host_updated: new_code_active | ¬restart_needed
6_verify_in_repl: require_with_reload | test_changed_functions
| some_changes → may_need(activate) call | re-registers_commands ∧ hooks
| skip(3:warnings) → silent_breakage | zero_warnings_policy
| skip(4) → stale_state | hooks_not_re_registered
| skip(6) → assumed_working | ¬verified
λ lm_tool_evaluation_sequence.
1_receive_code: from_language_model_api | string_input
2_validate_brackets: parinfer_check | balanced? | ¬eval_unbalanced
3_format_input: wrap_if_needed | prepare_for_sci
4_eval_in_sci: sci/eval-string | capture_output
5_format_result: value → confirmation_message | error → structured_error
6_return_to_model: tool_result | includes(value ∧ output ∧ error)
| skip(2) → unbalanced_code_crashes_sci | confusing_error
| skip(5) → raw_sci_internals_leak_to_model
1---2name: joyride-internals3description: Joyride extension internals — subsystem contracts, state architecture, activation sequences, and namespace reference. Use when: modifying core extension code, debugging state issues, working with app-db or SCI context, understanding activation or script execution flow, investigating nREPL or when-context behavior, or working with the output or disposable system.4---56# Joyride Extension Internals78Subsystem contracts, state architecture, and temporal sequences for the Joyride extension.910## Key Namespaces1112| Namespace | Purpose |13|---|---|14| `joyride.extension` | Entry point: activate, deactivate, hot-reload hooks |15| `joyride.db` | App state: `!app-db`, init-db, accessor functions |16| `joyride.sci` | SCI interpreter: namespaces, load-fn, eval-string |17| `joyride.config` | Path resolution: user-dir, workspace-dir |18| `joyride.lifecycle` | Activation scripts: user_activate, workspace_activate |19| `joyride.output` | Terminal output: ANSI colors, theme-aware, who-tracking |20| `joyride.when-contexts` | When-context management: `!db`, `set-context!` |21| `joyride.nrepl` | nREPL server: `!db`, middleware, bencode |22| `joyride.flare` | Flare API: panels, sidebars, hiccup, messaging |23| `joyride.flare.sidebar` | Sidebar provider: webview view registration |24| `joyride.flare.panel` | Panel creation: replicant rendering |25| `joyride.lm` | Language Model tool entry and registration |26| `joyride.lm.evaluation` | LM tool implementation: code execution, output capture |27| `joyride.lm.eval.core` | Pure functions: input validation, message formatting |28| `joyride.lm.eval.validation` | Pure validation: bracket check via parinfer |29| `joyride.who-tracking` | Evaluator awareness: cross-evaluator attribution |3031## Subsystem Contracts3233```34λ app_db_contract.35 db/!app-db ≡ atom {36 output-channel: OutputChannel37 output/terminal: Terminal38 extension-context: ExtensionContext39 invoked-script: string?40 disposables: [Disposable]41 workspace-root-path: string?42 flares: {key → FlareState}43 flare-sidebar-views: {slot → WebviewView}44 }45 | access_via_functions: (db/extension-context) (db/output-terminal) | ¬direct_deref_in_helpers46 | inspection_safety: (dissoc @db/!app-db :extension-context) | circular_ref_guard47 | mutation: swap! ∧ reset! | ¬deep_nested_mutation4849λ sci_context_contract.50 sci.ctx-store ≡ global_SCI_interpreter_context51 | !last-ns ≡ volatile | tracks_most_recent_evaluation_namespace52 | init: (sci.ctx-store/init ctx) at_activation | single_initialization53 | access: (sci.ctx-store/get-ctx) → SCI_context | thread_safe54 | features: #{:joyride :cljs} | reader_conditionals55 | classes: goog/global :allow :all | unrestricted_JS_interop56 | load-fn: symbol_libs(workspace→user_search) ∧ "vscode" ∧ "ext://..." ∧ node_require57 | alter-var-root: print_fn_capture/restore | ⚠ global_mutation_could_race5859λ nrepl_contract.60 nrepl/!db ≡ separate_atom | domain_isolation_from_app_db61 | server: middleware_based | start → port_file_written → accepting_connections62 | middleware_chain: standard_nrepl_ops(eval, load-file, interrupt, describe, completions, info)63 | session: clone_per_client | session_id_tracks_context64 | eval_protocol: { op: "eval", code, session, ns } → { status, value ∨ ex, ns, out, err }65 | when_context: joyride.isNReplServerRunning | set_on_start ∧ clear_on_stop6667λ disposable_lifecycle_contract.68 push-disposable!(disposable) → appends_to(:disposables @db/!app-db) ∧ context.subscriptions69 | clear-disposables!() → .dispose()_each ∧ reset_to_[]70 | activation_scripts: clear_before_re-run | idempotent_re-activation71 | command_registration: returns_Disposable → push_immediately72 | event_subscriptions: returns_Disposable → push_immediately7374λ output_system_contract.75 append-clojure-eval!(result-string) → output_terminal | ANSI_themed76 append-line-other-err!(error-string) → output_terminal | red_themed77 append-eval-result!(result ns who) → output_terminal | formatted78 | terminal: VS_Code_pseudoterminal | colored_output | theme_aware(light/dark)79 | who_tracking: evaluator_attribution | cross_evaluator_awareness8081λ when_context_contract.82 when-contexts/!db ≡ separate_atom | { context-key → boolean }83 | set-context!(key value) → vscode.commands.executeCommand("setContext" key value)84 ∧ swap!(when-contexts/!db assoc key value)85 | timing_invariant: set_context BEFORE creating_dependent_resources86 | sidebar_views: set_when_context_true → THEN_create_webview_provider8788λ hot_reload_contract.89 shadow-cljs: watches_src/ → compiles_on_save → hot_reloads_into_dev_host90 | before-load-async: cleanup_hook | called_before_hot_reload91 | after-load-async: reinitialize_hook | called_after_hot_reload92 | dev_host_restart: required_only_for_package.json_changes93 | state_preservation: app_atoms_survive_hot_reload | functions_replaced94```9596## Routing Reference9798```99λ script_execution_routing.100 script_path_resolution: workspace/src → workspace/scripts → user/src → user/scripts101 | first_match_wins | workspace_shadows_user102 symbol_lib(require 'foo.bar) → search(src_dirs) | namespace_to_path103 string_lib("vscode") → vscode_api_object104 string_lib("ext://publisher.extension") → extension_api_export105 node_module("some-npm-pkg") → node_require | commonjs_only106107λ evaluation_dispatch.108 code ∧ context → route_to_sci_eval_string109 | from_nrepl → session_bound | ns_tracked | print_fn_captured110 | from_lm_tool → bracket_validated_first | parinfer_check | ¬eval_unbalanced111 | from_activation_script → run_at_startup | errors_shown_in_output112 | from_command(run_code) → inline_code | quick_pick_selection113 | from_command(run_script) → file_resolved | executed_in_sci114```115116## Temporal Sequences117118```119λ activation_sequence.120 1_shadow_cljs_entry: extension.activate called | exports(activate)121 2_init_app_db: reset(!app-db) | store(extension-context ∧ output-channel)122 3_register_commands: vscode.commands.registerCommand | push_disposables123 4_set_when_contexts: joyride.isActive → true | enables_keybindings124 5_init_output: create_terminal_output | theme_colors_resolved125 6_init_nrepl: setup_server_infrastructure | ¬start_yet126 7_init_sci: configure_interpreter | namespaces ∧ classes ∧ load-fn127 8_run_activation_scripts: user_activate.cljs → workspace_activate.cljs | sequential128 9_ready: extension_fully_active | commands_available | repl_connectable129 | skip(7) → no_eval_capability | scripts_fail130 | skip(8) → user_customizations_not_applied | workspace_not_configured131132λ script_execution_sequence.133 1_resolve_script: path_resolution(workspace/src → workspace/scripts → user/src → user/scripts)134 2_read_source: vscode/workspace.fs.readFile | decode_utf8135 3_capture_print: alter-var-root(*print-fn*) → output_channel_writer136 4_eval_in_sci: sci/eval-string+ | with(ns ∧ file_metadata)137 5_handle_result: success → display_value | error → show_error_with_location138 6_restore_print: alter-var-root(*print-fn*) → original | ¬leak_print_capture139 | skip(1) → file_not_found | clear_resolution_error140 | skip(3) → output_goes_nowhere | or_goes_to_wrong_channel141 | skip(6) → print_fn_pollution | subsequent_scripts_mis_routed142143λ nrepl_server_lifecycle.144 1_user_starts: command(joyride.startNReplServer) | or_activation_script145 2_create_server: net.createServer | bind(port) | localhost_only146 3_set_context: joyride.isNReplServerRunning → true147 4_update_db: swap!(nrepl/!db) | store(server ∧ port ∧ clients)148 5_accept_connections: on(:connection) → create_session | bencode_transport149 6_handle_ops: eval ∧ clone ∧ close ∧ describe ∧ completions ∧ info | middleware_chain150 7_user_stops: command(joyride.stopNReplServer) | or_deactivation151 8_close_connections: close_all_client_sessions | drain_pending152 9_close_server: server.close() | unbind_port153 10_clear_context: joyride.isNReplServerRunning → false154 11_update_db: swap!(nrepl/!db) | clear(server ∧ port ∧ clients)155 | skip(3) → keybindings_dont_activate | ui_shows_wrong_state156 | skip(8) → orphaned_sessions | resource_leak157158λ flare_creation_sequence.159 1_set_when_context: sidebar_slot_enabled → true | BEFORE_view_creation160 2_ensure_provider: register_webview_provider_if_needed | idempotent161 3_create_view: resolve_webview | html_content_set162 4_render_hiccup: replicant_dom/render | hiccup → html163 5_setup_messaging: on_did_receive_message | bidirectional164 6_return_handle: {:panel ∨ :sidebar handle} | caller_can_post_message165 | skip(1) → race_condition | vscode_defers_view_creation | view_never_appears166 | skip(4) → empty_webview | content_not_rendered167168λ hot_reload_sequence.169 1_edit_source: modify_cljs_file | save170 2_shadow_detects: file_watcher_triggers | incremental_compile171 3_compile: cljs → js | check_for_warnings ∧ errors172 4_hot_reload_hook: ^:dev/after-load functions_called | state_preserved173 5_dev_host_updated: new_code_active | ¬restart_needed174 6_verify_in_repl: require_with_reload | test_changed_functions175 | some_changes → may_need(activate) call | re-registers_commands ∧ hooks176 | skip(3:warnings) → silent_breakage | zero_warnings_policy177 | skip(4) → stale_state | hooks_not_re_registered178 | skip(6) → assumed_working | ¬verified179180λ lm_tool_evaluation_sequence.181 1_receive_code: from_language_model_api | string_input182 2_validate_brackets: parinfer_check | balanced? | ¬eval_unbalanced183 3_format_input: wrap_if_needed | prepare_for_sci184 4_eval_in_sci: sci/eval-string | capture_output185 5_format_result: value → confirmation_message | error → structured_error186 6_return_to_model: tool_result | includes(value ∧ output ∧ error)187 | skip(2) → unbalanced_code_crashes_sci | confusing_error188 | skip(5) → raw_sci_internals_leak_to_model189```