From 091a25a76c4c76d33f34fdf698a46b44f9450aac Mon Sep 17 00:00:00 2001 From: egregore Date: Mon, 2 Feb 2026 12:28:57 +0000 Subject: [PATCH] Make rules configurable via API - Add Rules struct and rules.json data file - Read rules from file instead of hardcoding - Add GET /rules and PUT /rules endpoints Co-Authored-By: Claude Opus 4.5 --- src/main.rs | 48 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index e968462..5bbf6b0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -62,6 +62,11 @@ struct History { events: Vec, } +#[derive(Serialize, Deserialize)] +struct Rules { + rules: Vec, +} + #[derive(Serialize)] struct OrientResponse { project: ProjectInfo, @@ -117,6 +122,7 @@ fn health() -> Response { fn orient() -> Response { let status_path = PathBuf::from(DATA_DIR).join("status.json"); let history_path = PathBuf::from(DATA_DIR).join("history.json"); + let rules_path = PathBuf::from(DATA_DIR).join("rules.json"); let tickets_dir = PathBuf::from(DATA_DIR).join("tickets"); let context_dir = PathBuf::from(DATA_DIR).join("context"); @@ -170,6 +176,9 @@ fn orient() -> Response { .take(5) .collect(); + // Load rules from file + let rules_data: Rules = read_json(&rules_path).unwrap_or(Rules { rules: vec![] }); + let response = OrientResponse { project: ProjectInfo { name: "Egregore".to_string(), @@ -179,14 +188,7 @@ fn orient() -> Response { status, current_ticket, suggested_ticket, - rules: vec![ - "Claim a ticket before starting work".to_string(), - "Never commit secrets to git".to_string(), - "Always use the Python venv (~/.venv)".to_string(), - "Log completions to history".to_string(), - "Load context topics relevant to your ticket".to_string(), - "Commit and push changes to each service's git repo after modifications".to_string(), - ], + rules: rules_data.rules, available_context, recent_history, }; @@ -490,6 +492,32 @@ fn add_log(request: &Request) -> Response { } } +// ============================================================================ +// Rules +// ============================================================================ + +fn get_rules() -> Response { + let path = PathBuf::from(DATA_DIR).join("rules.json"); + match read_json::(&path) { + Some(rules) => json_response(rules), + None => json_response(Rules { rules: vec![] }), + } +} + +fn update_rules(request: &Request) -> Response { + let path = PathBuf::from(DATA_DIR).join("rules.json"); + + let rules: Rules = match rouille::input::json_input(request) { + Ok(r) => r, + Err(e) => return error_response(400, &format!("Invalid JSON: {}", e)), + }; + + match write_json(&path, &rules) { + Ok(_) => json_response(rules), + Err(e) => error_response(500, &e), + } +} + // ============================================================================ // Router // ============================================================================ @@ -526,6 +554,10 @@ fn handle_request(request: &Request) -> Response { (GET) ["/history"] => { get_history() }, (POST) ["/log"] => { add_log(request) }, + // Rules + (GET) ["/rules"] => { get_rules() }, + (PUT) ["/rules"] => { update_rules(request) }, + _ => Response::empty_404() ) }