<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Pathfinder UCD Engineering Notes]]></title><description><![CDATA[Source-backed notes on AI-assisted academic planning, local RAG, progress-aware consultations, and privacy-aware browser data boundaries.]]></description><link>https://pathfinder-ucd.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6a7c40bef7c8c2d7dab39bda/0ac912b3-230e-4a6f-9c48-3983777b54f1.png</url><title>Pathfinder UCD Engineering Notes</title><link>https://pathfinder-ucd.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Wed, 23 Sep 2026 21:36:13 GMT</lastBuildDate><atom:link href="https://pathfinder-ucd.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How Pathfinder UCD Works: From a Student Question to an Evidence-Aware Answer]]></title><description><![CDATA[Pathfinder UCD is an experiment in a very practical question:

Can an AI academic-planning conversation make its evidence, missing information, next actions, and access boundaries visible enough for a]]></description><link>https://pathfinder-ucd.hashnode.dev/how-pathfinder-ucd-works-from-a-student-question-to-an-evidence-aware-answer</link><guid isPermaLink="true">https://pathfinder-ucd.hashnode.dev/how-pathfinder-ucd-works-from-a-student-question-to-an-evidence-aware-answer</guid><category><![CDATA[RAG ]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[education]]></category><category><![CDATA[software architecture]]></category><dc:creator><![CDATA[richisblog]]></dc:creator><pubDate>Wed, 12 Aug 2026 10:27:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a7c40bef7c8c2d7dab39bda/f018e3a5-65f9-41dd-aee0-23443292cf67.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Pathfinder UCD is an experiment in a very practical question:</p>
<blockquote>
<p>Can an AI academic-planning conversation make its evidence, missing information, next actions, and access boundaries visible enough for a student to inspect and correct?</p>
</blockquote>
<p>This is not a claim that a language model becomes an academic adviser. It is a claim about workflow design. Academic planning is rarely one lookup. A student may need to combine a course prerequisite, a professor's review evidence, a major requirement, a change-of-major rule, a calendar deadline, a current section, a registration appointment, and personal constraints. If those pieces are mixed together in an ordinary chat, it is hard to tell which sentence is a confirmed fact and which sentence is a guess.</p>
<p>Pathfinder tries to make that distinction operational.</p>
<p>The public project is here: <a href="https://github.com/richisblog/Pathfinder-UCD">github.com/richisblog/Pathfinder-UCD</a>. The authoritative implementation notes are the repository's <a href="https://github.com/richisblog/Pathfinder-UCD/blob/main/docs/ARCHITECTURE.md">architecture guide</a>, <a href="https://github.com/richisblog/Pathfinder-UCD/blob/main/docs/FEATURES.md">feature guide</a>, and <a href="https://github.com/richisblog/Pathfinder-UCD/blob/main/docs/PROMPTS.md">prompt composition guide</a>.</p>
<h2>First, an important boundary: this is not hidden chain-of-thought</h2>
<p>When people ask “how does it think?”, there are two different things they may mean:</p>
<ol>
<li><p><strong>The observable workflow:</strong> which tool was called, what evidence came back, what remains unknown, what Todo item is next, and why the answer is blocked or ready.</p>
</li>
<li><p><strong>The model's private internal reasoning:</strong> hidden token-by-token reasoning that should not be treated as a product transcript.</p>
</li>
</ol>
<p>Pathfinder documents and displays the first. It does not claim to expose the second. The visible progress state is a compact, bounded consultation record; it is not a dump of private model reasoning. That distinction is important for both safety and intellectual honesty.</p>
<h2>The complete request lifecycle</h2>
<p>At a high level, one student message travels through the following stages:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a7c40bef7c8c2d7dab39bda/8c15a9a0-64c1-40ab-9f76-750d592821a7.png" alt="Observable Pathfinder UCD consultation lifecycle from a student question through Known, Unknown, Todo, clarification, read-only evidence, and the final answer" style="display:block;margin:0 auto" />

<p><em>The host-observable consultation loop. It is not a visualization of private chain-of-thought.</em></p>
<p>This is a description of the host-controlled workflow and the prompt contract, not a promise that a model can never make a mistake. The design makes a mistake easier to find: a reviewer can ask which tool result supported the sentence, which fact is still unknown, or which source was unavailable.</p>
<h2>1. A question arrives</h2>
<p>Consider a generic question:</p>
<blockquote>
<p>“I am considering changing my major to Psychology. What should I take next quarter, which professors are a good fit, and when can I register?”</p>
</blockquote>
<p>That sentence contains several dependent problems:</p>
<ul>
<li><p>eligibility and change-of-major requirements;</p>
</li>
<li><p>completed prerequisites and the student's current record;</p>
</li>
<li><p>course catalog facts for the next quarter;</p>
</li>
<li><p>professor and review evidence;</p>
</li>
<li><p>current sections and availability;</p>
</li>
<li><p>the student's registration appointment;</p>
</li>
<li><p>personal preferences such as workload or meeting times.</p>
</li>
</ul>
<p>The application does not need to call every tool immediately. The Pathfinder prompt tells the agent to distinguish a direct answer from a managed consultation. Greetings, capability questions, and one obvious lookup can stay direct. Comparisons, change-of-major eligibility, multi-quarter planning, and professor selection with several constraints should begin a managed consultation with two to six student-facing outcomes.</p>
<p>That classification is a workflow decision, not an accuracy score. It prevents the UI from showing a theatrical plan for “hello”, while making dependencies explicit for a real planning question.</p>
<h2>2. The Todo state becomes the public plan</h2>
<p>For the example above, a managed consultation might create this visible list:</p>
<pre><code class="language-text">1. Compare Psychology change-of-major requirements      in_progress
2. Confirm completed prerequisite courses               pending
3. Identify next-quarter courses that fit the goal      pending
4. Check professor and live section evidence            pending
5. Verify registration appointment and time zone        pending
</code></pre>
<p>The exact text is generated for the current student question; the important property is the state contract. The Pathfinder prompt asks for a full <code>todo_write</code> snapshot after relevant user answers, successful tool results, empty results, failed results, and Todo status changes. At most one item should be <code>in_progress</code> in a managed academic consultation.</p>
<p>The React desktop reads the latest successful top-level Todo snapshot. The Todo rail shows a completion count, pending/in-progress/completed labels, and the current active item. New incomplete work opens by default. When everything is completed, the rail collapses to a reviewable summary; the student can expand or dismiss it. The companion Known and Unknown sections are derived from the same full snapshot.</p>
<p>The host also keeps a canonical Todo state across turns. This matters when a student answers a clarification question later: the application can resume the same consultation instead of relying only on whatever the model happens to remember in a shortened prompt.</p>
<p>Source links:</p>
<ul>
<li><p><a href="https://github.com/richisblog/Pathfinder-UCD/blob/main/desktop/frontend/src/components/TodoRail.tsx"><code>TodoRail.tsx</code></a></p>
</li>
<li><p><a href="https://github.com/richisblog/Pathfinder-UCD/blob/main/desktop/frontend/src/lib/todoSnapshot.ts"><code>todoSnapshot.ts</code></a></p>
</li>
<li><p><a href="https://github.com/richisblog/Pathfinder-UCD/blob/main/internal/campus/native/tools.go"><code>internal/campus/native/tools.go</code></a></p>
</li>
</ul>
<h2>3. Known and Unknown are evidence states, not confidence vibes</h2>
<p>Pathfinder treats <strong>Known</strong> and <strong>Unknown</strong> as a strict evidence distinction.</p>
<h3>Known</h3>
<p>A Known item must come from one of two places:</p>
<ul>
<li><p>an explicit fact the student provided in the conversation; or</p>
</li>
<li><p>a successful result from a registered evidence tool.</p>
</li>
</ul>
<p>For example, “the student prefers a light workload” can be Known if the student said it. “The course requires ECS 036A” can be Known if the local course reader returned that prerequisite successfully.</p>
<h3>Unknown</h3>
<p>An Unknown item is a missing fact or access condition that can still change the answer. Examples include:</p>
<ul>
<li><p>completed prerequisites were not supplied;</p>
</li>
<li><p>the student said “summer” without naming Session 1, Special Session, Session 2, or Summer Quarter;</p>
</li>
<li><p>the local major database is not present;</p>
</li>
<li><p>Schedule Builder is not open or the extension is not paired;</p>
</li>
<li><p>personal schedule consent has not been granted.</p>
</li>
</ul>
<p>The rules deliberately reject several tempting shortcuts. A failed query is not Known. An empty result is not proof that a policy does not exist. General model knowledge is not a UC Davis-specific database row. A login blocker is not a student fact. The system keeps these conditions visible instead of smoothing them into a confident paragraph.</p>
<h3>Todo</h3>
<p>Todo is the action layer: what outcome still needs to be produced. Known and Unknown explain the evidence state; Todo explains the work state. A Todo item can be completed only after the relevant evidence and student-owned facts are resolved enough for the current goal.</p>
<p>The result is a small, inspectable ledger:</p>
<pre><code class="language-text">Known:   Psychology target major; student prefers a light workload
Unknown: completed prerequisites; current term section availability
Todo:    compare requirements; verify courses; check live schedule
</code></pre>
<p>This does not prove the answer is correct. It makes the answer's dependencies visible enough to challenge.</p>
<h2>4. Clarification is a first-class workflow action</h2>
<p>When a required value can only come from the student, Pathfinder should ask one narrow question and stop that turn. It preserves the current Todo state so the next answer can continue the same work.</p>
<p>Examples:</p>
<ul>
<li><p>“Which Summer term do you mean: Session 1, Special Session, Session 2, or Summer Quarter?”</p>
</li>
<li><p>“Which courses have you already completed?”</p>
</li>
<li><p>“Should I include your registered courses, your waitlist, or only public availability?”</p>
</li>
<li><p>“Which target major should I compare with your current major?”</p>
</li>
</ul>
<p>Why one question? A long questionnaire creates a new planning problem and makes it unclear which missing field is actually blocking the next evidence lookup. The implementation prefers the smallest student-owned fact that unlocks the next tool.</p>
<p>If the blocker is a source or access step rather than a student fact, the assistant reports a recoverable workflow status: open the browser, sign in, pair the extension, grant consent, provide a local dataset, or retry after a rate limit. These statuses are instructions, not evidence.</p>
<h2>5. What “RAG” means in this repository</h2>
<p>Pathfinder has a separate Campus UI RAG service and a main desktop agent path. Both use named read-only tools, but the control loops are different.</p>
<h3>Campus UI RAG loop</h3>
<p>The Campus UI builds a request containing:</p>
<ol>
<li><p>a dedicated Pathfinder system prompt;</p>
</li>
<li><p>the current Pacific time in <code>America/Los_Angeles</code>;</p>
</li>
<li><p>up to the last eight stored user/assistant messages;</p>
</li>
<li><p>the new user message;</p>
</li>
<li><p>the available tool schemas.</p>
</li>
</ol>
<p>The configured provider either returns a final answer or requests one or more tools. The service executes the tool calls, emits <code>tool_start</code> and <code>tool_result</code> events for the UI, appends bounded JSON results, and repeats for at most eight tool rounds. When the provider returns a message with no tool calls, the answer is stored in the local Campus UI store.</p>
<p>This path is tool-mediated RAG. The public snapshot does <strong>not</strong> claim to use a vector database, embeddings, or a learned semantic retriever in this path.</p>
<h3>Main desktop path</h3>
<p>The general Reasonix controller adds the Pathfinder academic prompt when campus data or a live schedule client is available. For managed work, it appends a bounded <code>&lt;consultation-progress&gt;</code> context containing the goal, Todo items, successful observations, next action, and completion criteria. The model then chooses the next read-only tool, and the host records the result in the conversation and evidence ledger.</p>
<h3>The tools and their sources</h3>
<table>
<thead>
<tr>
<th>Need</th>
<th>Tool examples</th>
<th>Source</th>
</tr>
</thead>
<tbody><tr>
<td>Professors and review evidence</td>
<td><code>search_professors</code>, <code>professors_for_course</code>, <code>professor_reviews</code>, <code>search_reviews_by_keywords</code>, <code>query_rmp_table</code></td>
<td><code>sqlite/rmp.db</code></td>
</tr>
<tr>
<td>Course facts</td>
<td><code>query_course_db</code></td>
<td><code>sqlite/courses.db</code></td>
</tr>
<tr>
<td>Major and change-of-major facts</td>
<td><code>query_major_catalog</code>, <code>query_change_major</code>, <code>compare_change_major_requirements</code></td>
<td><code>sqlite/majors.db</code>, <code>sqlite/changemajor.db</code></td>
</tr>
<tr>
<td>Academic dates</td>
<td><code>query_ucdavis_calendar</code></td>
<td><code>sqlite/ucdavis_calendar.db</code></td>
</tr>
<tr>
<td>Local policy text</td>
<td><code>search_txt_context</code></td>
<td><code>txt/*.txt</code>, <code>txt/*.md</code></td>
</tr>
<tr>
<td>Time and current schedule</td>
<td><code>convert_pacific_time</code>, <code>query_live_schedule</code></td>
<td>Local time logic and optional browser bridge</td>
</tr>
</tbody></table>
<p>The database files are read locally. The provider receives only the prompt, conversation context, and selected evidence for the current request. It does not receive the entire SQLite file by default.</p>
<h2>6. How relevant results are selected</h2>
<p>“Most relevant” needs to be described precisely because it is easy to imply a more advanced retrieval system than the code actually contains.</p>
<h3>Structured SQLite tools</h3>
<p>The structured tools expose bounded arguments such as course code, major name, department, filters, search fields, sort order, and result limits. The runner maps those arguments to allow-listed columns and query shapes. Several services use case-insensitive <code>LIKE</code> matching and explicit ranking rules. The major catalog comparison tool can rank exact major-name matches before broader filename/text matches. The tool returns a bounded set of rows or cards for the model to compare.</p>
<p>The model's tool choice is part of relevance: it should not use a professor review query to answer a calendar question, and it should prefer <code>compare_change_major_requirements</code> before separate narrow lookups when the question compares majors.</p>
<h3>Local TXT/Markdown search</h3>
<p><code>search_txt_context</code> tokenizes the query, ignores one-character tokens, searches each <code>.txt</code> and <code>.md</code> file, counts case-insensitive term occurrences, sorts matches by score (then source name), and returns a bounded excerpt. This is a transparent lexical scorer, not embedding similarity. It is intentionally simple enough to inspect and test.</p>
<h3>Live Schedule Builder results</h3>
<p>The browser adapter does not rank a global web index. It requests a specific term/course from the supported Schedule Builder page, normalizes the returned sections, and includes source URL, provider version, fetch time, and freshness. The model then combines that live evidence with stable local catalog facts.</p>
<p>So the honest description is: relevance comes from a combination of query planning, allow-listed structured filters, deterministic local scoring, bounded limits, and the model's evidence comparison. It is not a claim of a universal semantic ranking engine.</p>
<h2>7. Evidence returns to the consultation loop</h2>
<p>After a tool result, the agent must distinguish three cases:</p>
<ol>
<li><p><strong>Success:</strong> evidence can support a Known item or complete a Todo.</p>
</li>
<li><p><strong>Empty evidence:</strong> the query returned no matching rows; this is a gap, not proof of nonexistence.</p>
</li>
<li><p><strong>Failure or blocked access:</strong> preserve a concise Unknown condition and ask for a recovery step.</p>
</li>
</ol>
<p>The prompt tells the model to update the full Todo/Known/Unknown snapshot after material changes, then choose exactly one next action. It should not call a tool merely to create visible activity, and it should not repeat an identical successful query. The main campus runner may reuse identical successful results from an in-memory cache, but cached evidence remains an observation tied to the same tool and arguments.</p>
<p>The final answer should include:</p>
<ul>
<li><p>the practical conclusion;</p>
</li>
<li><p>which campus facts were grounded by tools;</p>
</li>
<li><p>what remains student-owned or source-owned Unknown information;</p>
</li>
<li><p>caveats about freshness, access, or interpretation;</p>
</li>
<li><p>a concrete next action.</p>
</li>
</ul>
<p>That structure is designed to make an answer useful even when the correct answer is “we need one more fact before deciding.”</p>
<h2>8. Schedule Builder and the official UC Davis page</h2>
<p>The Schedule Bridge is a read-only, user-controlled adapter. It does not pretend to be an official UC Davis API and it never submits enrollment forms.</p>
<img src="https://cdn.hashnode.com/uploads/og-images/6a7c40bef7c8c2d7dab39bda/0c0a205f-4efe-4e77-9773-73a2b7813242.png" alt="Read-only Schedule Builder bridge trust boundaries from Pathfinder through the local bridge and paired extension to the signed-in university page" style="display:block;margin:0 auto" />

<p><em>Only normalized academic evidence returns; sensitive page-session material stays inside the university page boundary.</em></p>
<h3>Public section search</h3>
<p>For a six-digit term code and a course identifier, the extension uses the supported Schedule Builder search endpoint through the page's own origin. It normalizes fields including CRN, section, title, units, instructors, meeting times, enrollment/waitlist counts, prerequisites, general-education notes, drop rules, final-exam dates, and notes.</p>
<p>The request handler uses a queue with a minimum delay and jitter between course requests, caches public live results for the session, and returns <code>source_url</code>, <code>provider_version</code>, <code>fetched_at</code>, and <code>freshness: "live"</code>.</p>
<h3>Personal context</h3>
<p>Registered courses, waitlisted courses, and Pass 1/Pass 2 appointments are personal categories. They require explicit consent for the current Pathfinder conversation. Pass appointments are parsed into a Pacific instant with <code>PST</code> or <code>PDT</code> and an explicit UTC offset. The prompt warns that an appointment is not automatically a registration deadline or an open-registration period.</p>
<p>The page adapter runs in the <code>MAIN</code> world because the university page owns the authenticated same-origin session. The returned object is deliberately narrow: PIDM, cookies, request headers, raw HTML, browser profiles, and HAR/session exports stay inside the page boundary. The extension never uploads a browser profile or changes enrollment.</p>
<h3>Fail-closed behavior</h3>
<p>The bridge uses a short-lived pairing code and binds the connection to the extension ID. It listens on loopback only. If the browser is not open, the user is not signed in, pairing is missing, consent is absent, the site rate-limits a request, or the response format changes, the result is a named recoverable status such as <code>BROWSER_REQUIRED</code>, <code>LOGIN_REQUIRED</code>, <code>PAIRING_REQUIRED</code>, <code>CONSENT_REQUIRED</code>, <code>RATE_LIMITED</code>, or <code>SITE_VERSION_UNSUPPORTED</code>.</p>
<p>The last status is especially important: if the school's page changes, the adapter stops instead of guessing where the fields moved.</p>
<h2>9. Where memory enters the context</h2>
<p>There are two different kinds of “memory” in this codebase, and conflating them would make the architecture sound more magical than it is.</p>
<h3>Campus UI conversation history</h3>
<p>The dedicated Campus UI stores its local threads and messages in the private <code>pathfinder.db</code> runtime store. For a new RAG request, the service reads the last eight user/assistant messages from that thread and sends them with the current question, the RAG prompt, current Pacific time, and tool schemas. It does not send the entire database file to the provider.</p>
<h3>Reasonix sessions and context compaction</h3>
<p>The general Reasonix agent maintains a session message list. As a prompt approaches the provider context window, the kernel can compact older middle history while preserving a bounded recent tail and archiving originals under private runtime state. This protects token limits without putting a session export into the public repository.</p>
<h3>Memory v5 execution compiler</h3>
<p>The inherited Reasonix kernel also contains a local Memory v5 execution compiler. Its lifecycle is more specific than “the AI remembers everything”:</p>
<ol>
<li><p>At boot, the compiler runtime is created under a project-scoped private user state directory when the configuration enables it.</p>
</li>
<li><p>On a new agent turn, a task classifier decides whether the input is an actionable task or ordinary chat. Greetings and small conversational turns can skip the compiler.</p>
</li>
<li><p>For an eligible task, <code>StartTurn</code> loads prior compiler state, summarizes the goal, builds a bounded Planner IR containing constraints, strategy selection, memory references, steps, and risk notes, and creates a turn trace.</p>
</li>
<li><p>Depending on the configured injection mode and throttling gate, the compiled execution contract may replace the visible user turn sent to the provider. Otherwise the compiler still observes and records the turn without injecting that contract.</p>
</li>
<li><p>Tool calls and results are recorded against the turn. On completion, the runtime writes bounded local trace and learning files and updates strategy or memory state for future tasks.</p>
</li>
<li><p>The UI can expose local memory citations and content-free metrics when the compiler actually influenced a turn.</p>
</li>
</ol>
<p>The compiler does not rewrite the stable system prompt or tool schemas. It does not turn the model's private reasoning into a public transcript. It is a local, rule-driven execution-memory layer that can learn from task traces, successful and failed tool outcomes, and reusable strategies.</p>
<p>Most importantly for Pathfinder: the academic <code>&lt;consultation-progress&gt;</code> block is a separate feature. It is built from the current academic goal, Todo state, bounded successful campus observations, and the next action. It is not the same thing as Memory v5, and the separate Campus UI RAG path uses its own recent history/tool loop rather than the full desktop agent compiler path.</p>
<h2>10. The final answer is a handoff, not a verdict</h2>
<p>For the example major-planning question, a responsible final response might look structurally like this:</p>
<pre><code class="language-text">Recommendation
  The local change-of-major evidence supports checking A and B next.

Evidence used
  - change-major comparison: successful local query
  - course prerequisite: successful catalog query
  - current section: live Schedule Builder result, fetched at [time]

Still unknown
  - completed prerequisite course list was not supplied
  - the student's personal pass time was not requested / consented

Next action
  Send the completed prerequisite list, then verify the live section again
  before treating the plan as registration-ready.
</code></pre>
<p>The wording will vary by model and language preference, but the contract is stable: do not invent a campus fact after an empty or failed lookup, state the remaining unknown, and give the student a concrete next step.</p>
<h2>What this project does not claim</h2>
<p>Pathfinder UCD is a research and educational application, not official university advising and not a commercial decision system. It does not claim benchmark performance, perfect freshness, institutional approval, or universal semantic retrieval. The public snapshot excludes chat transcripts, provider key values, runtime databases, personal records, papers, and private research material. The source still contains reusable DeepSeek-Reasonix kernel code; the academic support promise is limited to the documented Pathfinder surface.</p>
<p>That restraint is part of the design. A project meant to help students make real decisions should make it easy to see where its evidence ends.</p>
]]></content:encoded></item></channel></rss>