JakeShare

January 2026
  January 26
    Progress on dot-path search/resolution
      I think I finally fully understand the issues. I've updates in flight for the PR where I started this work a few days ago.
      tl;dr: Confusion between ODB lookups and EFP lookups were causing EFP table entries to mask the "real" ones.
      Next step is to get this merged, and do a bunch of manual testing with the REPL.
        After that I may do somethin light to clear my head. This one was a slog.
    Dave: Thanks for reaching out to Ted on Masto
      I replied back. Hopefully he'll at least follow along, if not contribute directly.
    Previous TODOs
      Why does string(someExternal) fail? That's tonight's first challenge. (WIP)
        Issue: When string() is called, the path resolution doesn't seem to find system.globals.string and instead finds system.verbs.builtins.string. I passed this theory to the architect agent, and they're investigating…
        The system is quite messed up now. We regressed the ability to call anything that's not defined in system.compiler.language.builtins which call into kernel implementations by token. The globals and builtins are all broken.
        Going to use git bisect to find the commit that broke us next.
      … and then to do some housekeeping on integration tests… (on hold)
      … and finally to get back to booting up inetd and builtins.webserver (on hold)
      In the background, I gave a separate Claude instance very detailed instructions on an extensive docs updating project.
        I told it that it was pre-work for a VP-level quarterly review.
        I explained that this wasn't *real* but to write the doc anyway, and that the review is a great thought-framing exercise.
        We'll see how it does!
    Other Carry-Over
      Dave: Thanks for the JSON stuff.
        http://scripting.com/publicfolder/misc/jsonStuffForJake2.zip
        Regarding other verbs, I think I'm going to get to a point pretty soon here where I could do it myself.
          I have a plan for making frontier-cli work as a long-running process.
          Once that's done I could just open opml.root and extract from there.
          ETA is probably a few days. We can discuss when we talk tomorrow.
      Summary of Frontier accomplishments over the last few days
        REPL, baby!
          Make frontier-cli able to run as a long-running process interactively when launched in a terminal. REPL, baby! (v1 DONE)
            First step here is a design discussion. (done)
            Then a detailed planning doc. (done)
              REPL_INTERACTIVE_MODE_DESIGN.md
            Then implementation and testing. (done)
              The plan is in 4 phases. As of this writing Phase 2 is done, and phase 3 (the actual REPL) is in progress.
            This will be a huge milestone -- the first time you could do something truly useful with the app!
        Script verbs are 100% complete
        Sys verbs are 100% complete
        Html verbs are 100% complete
        Xml verbs are 100% complete
        Sys verbs are 100% complete
        Op verbs are 100% complete
        Fixed external variable scope resolution (an old bug)
        Lang verbs are 100% complete
        Rgb, point, rectancle, semaphore, and base64 are all 100% complete
        Db verbs are 100% complete
        Refcons are now packed 64-bit aligned just like the rest of the odb (this was a big one)
        Applied for an LLC and bought a couple of domain names to go with it
        Previously completed to 100%: clock, crypt, date, db, file, lang, mainwindow, math, string, table, target
        Overall verb coverage is now (at least) 52%
        A significant Claude Code workflow advancement for me!
          I gave instructinos in CLAUDE.md about how and when to use sub-agents.
          The basic idea is to choose the agent that matches the task, and to parallelize work whenever possible.
          Claude can now delegate to up to (arbitrarily) 10 sub-agents in parallel at once.
          Coupled with test-driven development (TDD) my flow is now:
            1. Spin up a branch and worktree, and investigate and plan work
            2. Have Claude write integration tests
            3. Spawn multiple sub-agents to work in parallel
            4. Summarize the work
            5. Have the PR writer agent create and push a PR
            6. Run a shell script that monitors for feedback from the review bots (Claude, Codex, and Cursor)
            Steps 2 through 6 can happen in a single prompt!
          I just implemented 12 sys verbs in about 25 minutes with this new process. Most of the time spent was planning.
      Running Frontier TODOs
        Build and test
          Reorganize existing tests by feature/component
          Integration tests (first for table verbs) ✅ (ongoing)
          UserTalk test runner infra ✅
          Integrate with the test makefile ✅
        Architecture
          Complete the de-globalization - #135, #94, #86 (in progress)
            Outline push/pop stack (oppushoutline/oppopoutline) still used throughout codebase (24+ files)
            Other global state pockets likely exist
          Integrate callback guards with table symbol mutation tracking - #169
          Refactor dbendsaveas to make implicit disposal explicit - #138
          Design API for IPC with GUI application. (started, needs lots of work)
            Needs to be performant
            Bi-directional messaging
            Debugging capability
            Works over TCP/IP (transport and line-encoding TBD)
        Bug fixes
          Reference counting for table_context_t for concurrent access - #168
          Build issue: upbit/downbit/leftbit/rightbit conflicts - #186 (done)
          time_t portability using 64-bit rtime representations - #167 (done)
        New Glue scripts
          Pre-requisites: v7 root format is stable and we have 2-way communication with a long-runnint process. (in progre3ss)
          Add glue scripts for new table verbs
          Search open issues (esp P0s/P1s) for others
        Long-term
          Long-running process - #86 (in progress)
            Messaging API(s)
            Control process
          Get networking to work - #88 (coming soon!)
            Outbound
            Daemons - #122
            Security
          Unicode support - #91
          UI API(s) - #85
          Get rid of filespecs if there's still a performance issue
          Pick a better hash algorithm - #93
          Multi-user support
            Daemon process design - #106
            Migrate user tables to user.root
            Figure out what to do about the user.prefs table since some startup code expects it
            Can we use scns to refactor UserTalk code that expects to initialize and see user-owned data over the network? - #97
        Future / Nice-to-have
          Update regex, sqlite, and postgres libs or find an alternative integration method
          Investigate Python and JavaScript integration with UserTalk runtime
          Investigate OSA integration for AppleScript support on macOS
  January 25
    I now know more than I ever thought I wanted to know about the way scripts are located, compiled, and called in the kernel.
      I now understand why some kernel verbs are resolved via system.compiler.language.builtins (these are resolved via EFP table/token).
      I also understand the ins and outs of both the search order, and the lifecycle of an uncompiled glue script (non-EFP).
      It feels like I'm very close to cracking this one. I've been doing a lot of handholding to get Claude to this point.
        We'll see if it pays off!
        (Also, I'm very glad I took a night course in the Fundamentals of C Programming in 1998!)
    Claude is still very stuck on the path resolution logic.
      I resorted this morning to adding more rules to my workflow and to general guidance.
      Running git bisect again to figure out where the breakage really started.
    Dave: Agreed regarding jump
      My workaround back in the day was to jump to builtins.string, but yeah it's a pain-point.
      I'd prefer to not implement some one-off workaround to solve this case.
      Also obviously we can't change the precedence of entries under system.paths.
      I'll marinade on it...
      Also: Ack. I won't do anything unless some surprising idea comes to me.
  January 24
    Finally! Got the bug fixed last night for the address lookup logic and confirmed this morning.
      There were many misunderstandings and workarounds in the code that Codex originally wrote, and Claude later updated for bootstrapping the project.
      Turns out that now that the database layer is solid, and we're loading the real Frontier.root (with auto-migration), a lot was still borked.
        For example, at the start of Wed, defined(webserver) was true, and defined(webserver.init) was false … WHAT?!?
        The thing that finally helped sort all of this out was that sizeOf(webserver)==7 and sizeOf(builtins.webserver)==21 !
        Why? Because in the kernel there was a workaround from very early on to add webserver to the EFP table very early, and langsearchpathvisit() was ALSO incorrectly looking in the EFP table first, before searching paths in system.paths.
        And then once that was fixed it took another few hours to figure out that even though the fixed langsearchpathvisit() was searching via system.paths first, it was sorting in storage order, not in alphabetical order.
        With those two critical fixes, we disabled the EFP table entirely in the headless runtime, and now it appears to be all working as expected.
        But... string(webserver.init) still fails. That's the next challenge. (See TODOs above)
    And while I was out on a short flight with Gabe and mom today, Claude added a lot of inline documentation in comments in the kernel.
      Three reasons for this: 1) it helpes Claude to investigate and implement more quickly, 2) it helps me understand the code better, and 3) it helps any possible future contributors to learn and understand how the kernel works, along with extensive documentation already written.
      But said extensive documentation also needs a big clean-up push. (WIP)
        Doing this in the background now.
        The code is done when the code works and when the docs are complete and accurate.
  January 22
    I have some meetings and business calls today. I'll be busy most of the afternoon, but will pick up work again after dinner.
      Good news is that I got some of the stability issues I mentioned yesterday fixed.
      Still tracking to a goal of getting inetd and the web server running.
  January 21
    I have yet another migration bug it seems.
      I found that webserver.init couldn't be found but builtins.webserver.init could.
      Debugging this it looks like the address value migration code has a bug that causes some corruption, which in this case was manifest in the search paths in system.paths.
      That'll be tonight's project.
      But on the bright side, lots of progress on threading and networking. If I get over this hump I just might be able to start the webserver.
        When I get to that point I'll do another REPL release.
  January 20
    It's time for me to start looking at networking
      Planning docs are in place. DONE
      Threading (a prerequisite) is proven to work. DONE
      Callbacks with parameters (also a prerequisite). DONE
      Getting the basic networking to work is planned once the callback system is done. IN PROGRESS
        Basic client-side networking code is working. DONE (not fully tested yet)
        Working now on tcp.addressEncode/Decode, then tcp.listenStream and tcp.acceptStream.
        After that, migrating network tests to localhost since we will have both client and server side networking.
          Very close now: 33 of 34 integration tests are passing!
          Once I'm at 100%, theoretically I should be able to fire up the http server. 🤞
    Working on completing the thread.* verbs – the basics are there, but there are still gaps.
      Code is written and PR is up but there are a bunch of problems.
      Fixing integration tests first. (Turns out I think this is relatively easy.)
        Db Migration (db_migration)
        Db Verbs (db_verbs)
        Dialog Verbs (dialog_verbs)
        File Dialog Verbs (file_dialog_verbs)
        File Verbs (file_verbs)
        Html Core Tests (html_core_tests)
        Html Framework Tests (html_framework_tests)
        Html Image Tests (html_image_tests)
        Html Text Processing Phase2 Tests (html_text_processing_phase2_tests)
        Lang Verbs (lang_verbs)
        Op Verbs (op_verbs)
        Opattributes Verbs (opattributes_verbs)
        Repl Basic (repl_basic)
        Repl Commands (repl_commands)
        Repl Sessions (repl_sessions)
        Runtime Parameter State (runtime_parameter_state)
        Script Processor Verbs (script_processor_verbs)
        String Verbs (string_verbs)
        Sys Environment Verbs (sys_environment_verbs)
        Sys Processor Tests (sys_processor_tests)
        Table Sorting Verbs (table_sorting_verbs)
        Table Verbs (table_verbs)
        Target Verbs (target_verbs)
        Thread Verbs Foundation (thread_verbs_foundation)
        Xml Verbs (xml_verbs)
  January 19
    LLC is all set up 🎉
      I got the LLC application approval, and filed for a tax ID.
      Bank account is set up.
      No website yet, but email is working at jake@couleslabs.com.
    Dave: Let me explain a little more about the OPML files
      They're not the object database. The file linked below is the export of the integration test metadata.
        They're broken down into categories. Each category is an outline containing the UserTalk scripts and associated data that runs automated tests that validate that verbs and other core headless functionality are working.
        The test framework itself and the scripts that do the tests are all written by Claude.
        I did export all of the glue scripts in Frontier.root to text files so that the AI agents can see it since early on the runtime wasn't working reliably enough for them to look inside Frontier.root directly.
        I also exported the source outlines for docserver for the AI agents to see so that they understand what the verbs are supposed to do.
        Both the glue code and docserver source are committed to the GitHub repo along with docs and AI instructions to enable anyone to follow a similar workflow to the one that I'm using, for visibility into planning and roadmap, and to ensure that the project can be built on any machine.
        Claude relies pretty heavily on Python scripts to do a lot of things from editing code to creating tools to help it accomplish tasks.
        There's no Python in headless Frontier, but there are some Python scripts in the build and test pathways.
    Changed the strategy for generating the OPML for the integration tests
      The single-file approach was causing merge conflicts and the files were huge.
      Solution: inclusion. Insteat of one giant file, create a top-level file and link to categories, then scripts.
      Here's the new (final) canonical URL:
        https://raw.githubusercontent.com/jsavin/Frontier/develop/reports/integration_tests.opml
          Db Migration (db_migration)
            Database migration - source file unchanged - Migration should not modify v6 source database file
              Metadata
                expected_result: True
                skip: True
                reason: Requires external CLI invocation to test migration - use system test instead
              Script
                local(src = "{FRONTIER_TEST_TMP_DIR}/test_v6.root")
                local(dst = "{FRONTIER_TEST_TMP_DIR}/test_v6.root7")
                local(src_hash = "")
                local(src_hash_after = "")
                // Copy original system root as test source
                file.copy("{SYSTEM_ROOT_V6}", src)
                // Get hash of original source file
                src_hash = file.md5(src)
                // Run migration via CLI (this is tested externally via CLI invocation)
                // For now, just verify source file exists and is readable
                return file.exists(src)
            Database migration - creates v7 destination - Migration should create valid v7 destination file
              Metadata
                expected_result: True
                skip: True
                reason: Requires external CLI invocation to test migration - use system test instead
              Script
                local(dst = "{FRONTIER_TEST_TMP_DIR}/migrated.root7")
                // Verify file doesn't exist yet
                if file.exists(dst)
                file.delete(dst)
                return !file.exists(dst)
            Database hydration - opens correct file after migration - Hydration should open v7 file, not v6 source
              Metadata
                expected_result: True
              Script
                // This tests the fix for the local variable bug
                // After fix, hydration opens hydration_path (which points to v7),
                // not the const parameter path (which pointed to v6)
                // Load system root (auto-migrates if needed)
                return typeof(system) == 'tabl'
            Database - system table accessible after hydration - System table should be fully accessible after hydration
              Metadata
                expected_result: True
              Script
                return sizeOf(system) > 0 &&
                sizeOf(system.compiler) > 0 &&
                sizeOf(system.verbs) > 0
            Database - workspace accessible after hydration - Workspace table should exist and be writable after hydration
              Metadata
                expected_result: True
              Script
                workspace.test_flag = true
                return workspace.test_flag == true
          Db Verbs (db_verbs)
          Dialog Verbs (dialog_verbs)
          File Dialog Verbs (file_dialog_verbs)
          File Verbs (file_verbs)
          Html Core Tests (html_core_tests)
          Html Framework Tests (html_framework_tests)
          Html Image Tests (html_image_tests)
          Html Text Processing Phase2 Tests (html_text_processing_phase2_tests)
          Lang Verbs (lang_verbs)
          Op Verbs (op_verbs)
          Opattributes Verbs (opattributes_verbs)
          Repl Basic (repl_basic)
          Repl Commands (repl_commands)
          Repl Sessions (repl_sessions)
          Runtime Parameter State (runtime_parameter_state)
          Script Processor Verbs (script_processor_verbs)
          String Verbs (string_verbs)
          Sys Environment Verbs (sys_environment_verbs)
          Sys Processor Tests (sys_processor_tests)
          Table Sorting Verbs (table_sorting_verbs)
          Table Verbs (table_verbs)
          Target Verbs (target_verbs)
          Thread Verbs Foundation (thread_verbs_foundation)
          Xml Verbs (xml_verbs)
  January 18
    Fixed a segfault in file I/O last night
      Integration tests are now back to 100% passing.
  January 17
    PR #317 lays a foundation for true thread safety
      It's a pre-requisite for both networking and agents to function properly. Completion report below:
        ✅ Completed Thread Registry Work
          PR #317 Status: ✅ MERGED to develop with full test validation
        Key Accomplishments:
          1. ✅ Fixed thread registry implementation with 8 comprehensive commits
          2. ✅ Addressed all critical thread-safety issues (use-after-free races, deadlock prevention)
          3. ✅ Integrated allocate_thread_id() into allocate_thread_record()
          4. ✅ Fixed get_thread_count() initialization race condition
          5. ✅ All 15 unit tests passing
          6. ✅ Full test suite validation (no regressions)
          7. ✅ Deleted local worktree
      Just finished it up and unit tests are passing 100%. (The are the low-level C kernel tests.)
      Now looking at some unrelated integration test failures. (These are the higher-level tests written in UserTalk.)
    Dave: Thanks for the mention to Matt (ps. ack)
      Did Matt have any thoughts about this? Feel free to point him at the repo if he's interested.
  January 16
    Tonight's project: Threading and networking (still in progress on 1/17)
      1. Deep dive on what's there
      2. Planning docs (my system architect agent is writing and organizing 11 of them)
      3. Multiple implementation phases
      Probably multiple PRs for this one -- maybe 5 or 6. Unlikely to finish today.
    Dave: On the REPL release
      You're welcome to try it out. It doesn't do a lot yet, and there's a lot of annoying log-spew still.
      The main reason for doing it was to prove out that I can drive releases through GitHub using Claude.
      I did some enhancements on it this afternoon (reduced log noise, implemented editing, and tab-completion like bash/zsh).
      I'll probably do another release shortly before you wake up on Saturday.
    It's been quiet here today. I had a bunch of personal stuff to do and did a little programming on another project.
      I have an idea for an MCP server that I could release as a core open source project.
      Paid tier(s) later once I prove out its usefulness.
      (I need to start generating some revenue. ;-)
    It's going to be quiet here tomorrow during the day as well.
      Gabe is taking me on a flight! (Cessna 172)
      I'll probably get to fly a little too and maybe do a take-off. (Landings are an advanced skill!)
  January 15
    Just updated the Frontier readme on GitHub:
      https://github.com/jsavin/Frontier
    First (semi-private) release of Frontier with REPL is here:
      https://github.com/jsavin/Frontier/releases/tag/v1.0.0-alpha.2
      The release includes install instructions.
        I'll be using this process in the future when key functionality becomes available.
        Next up: Networking!
      It's only got the migrated Frontier.root (right now Frontier.root7), and doesn't run startup scripts or try to load anything else.
      From the bot: ✅ Release v1.0.0-alpha.2 Published Successfully
        What was accomplished:
        1. ✅ Updated CHANGELOG.md - Documented the critical upgrade safety fix
        2. ✅ Committed changes - Pushed CHANGELOG update to develop
        3. ✅ Created and pushed tag - v1.0.0-alpha.2
        4. ✅ GitHub Actions workflow - Built and published release successfully (1m 12s)
        5. ✅ Updated release notes - Highlighted the critical fix and upgrade instructions
      Note: I haven't tested the install flow for the release! It's not high on my TODOs right now. I will get to it tomorrow.
        YMMV, Your mother loves you, etc.
    Dave: Thank you for your very kind words on Scripting News!
  January 14
    Bing! I have a Frontier REPL!
      I can run this in the terminal and land in a text-based Frontier runtime: frontier-cli --system-root ./Frontier.root
        I get a prompt like [root]> where root is the default target -- the top level of Frontier.root
        I can type 1+1 and hit enter and it returns 2
        I can type defined (workspace.notepad) and it returns true
        I can type system.temp.foo = "bar" and then return(system.temp.foo) and it returns "bar"
      What doesn't work? Probably lots of stuff...
        The first one I tried was string (workspace.notepad) which triggered an error in db.c.
        We'll see soon what else...
      Ps. REPL stands for Read–Eval–Print Loop. It’s an interactive programming environment that:
        1. Read – takes user input (code)
        2. Eval – evaluates/executes that cod
        3. Print – displays the result
        4. Loop – repeats the process, allowing rapid experimentation
      The main difference between this REPL and others like the browser console is that locally declared variables are destroyed as soon as the thread returns. Instead it works like the QuickScript window.
        Most modern REPLs keep locals around until you do something like /clear
        Why? Because I still have a bunch of push/pop state management to clean up.
          It's all release-blocking work, but it's heavy lifting and potentially destabalizing, and I want to get more core stuff working first.
    Nate B Jones on Claude Cowork (new product from Anthropic)
      It's basically exactly what I'm doing in the terminal, but for non-tech folks
      YouTube: Task Queues Are Replacing Chat Interfaces
      Anthropic's Getting Started with Cowork
    Here's an interesting doc: Summary of the legacy frontier webiste framework architecture:
      docs/WEBSITE_FRAMEWORK_ARCHITECTURE.md
      I feel like I'm replaying the development of Frontier since around 1992. ;-)
        I was there and watching all of it.
      Claude Code's credit at the end is interesting... 😉
        "Last Updated: 2026-01-14 Contributors: Claude Code (documentation), Dave Winer (original design), UserLand Software (implementation)"
  January 13
    Claude Code and slash-commands (important workflow improvements)
      Claude Code lets you create your own / commands by defining them in .claude/commands/
      I created two today, one called "/doit" which follows my standard process, and one called "/tidy" which cleans up branches/worktrees after finishing a chunk of work.
        These will save a lot of typing and stopping the AI to correct behavior that I forgot to mention.
        Workflow is now: 1) create and iterate a planning doc, 2) /doit, 3) /tidy.
        It does test-driven development with parallel sub-agents to speed up implementation, and automatically pushes a PR and monitors for review feedback.
      /doit has a couple of interactive steps where it asks for guidance if there's a choice to make.
      I'm using this to implement the headless long-running process plan now.
    Sick today. Teenager brought it home to us from college. Ugh.
      Feeling better this evening after a long afternoon nap, some comfort food, and cold medicine.
  January 12
    Dave: Do you have a JSON implementation in the OPML editor?
      Pretty sure you do. 😉
      Can you give me pointers to it? (I'll probably have to set up a legacy Mac VM to extract it from the OPML Editor world.)
      Also as an aside, I know you were doing updates some years ago to verbs in the OPML editor. It would be great to get that stuff into my flow too. I don't want to lose any important work!
      And: Who is Betty named after? The Flintstones character? Betty Boop? Someone else?
    I set up JakeShare archives for 2025 and linked them in below
  January 10
    Dave:
      Just read the "Software Library with No Code" post...
        That's basically what I'm doing with Frontier, but there are literally hundreds of specs.
        For each thing I want to do, I work with Claude (almost exclusively recently), to write a high-level strategy doc.
        For anything complex I take that strategy doc and work with Claude again to create a detailed execution plan.
        The agents all have their own markdown files defining what they're good at and when to use them.
        Then my typical execution prompt is something like: "Implement X following plan Y. Work methodically, step by step. Use the appropriate sub-agent for each task, and parallelize when possible. When you're done, run the full test suite and then summarize for me what progress was made and the status of the tests. If you get stuck on something complex, please stop and ask me for help."
        I can usually get 15 to 30 minutes of work from this at a time, which is the rough equivalent of a mid-level C engineer working for maybe 1/2 a day.
      Also, I totally recognize the opVisitAll pattern ;-)
    Today's work
      Done
        Outline refcon data is now 64-bit aligned just like everything else
        Fixed a set of critical issues in db verbs
          Guarded against incorrect use of the global, mutable database context and wrote a plan for completely eliminating it
          db.open automatically migrates v6 roots to v7, but keeps the v6 database around as a backup
        Lots of op verbs implemented
        Implement db verbs
        Finish up op verb implementation
  January 8
    Regarding Frontier and SQL
      The database is fundamentally not schematized like SQL is, but I could imagine that for some tables it could be made to work.
        I'll ask Claude about this!
      I know Brent had talked previously about options like SQLite for ODB storage (or even the filesystem): I want it but it's far away right now.
        I still have aspirations to do this -- make the database in Frontier "pluggable" so you could use the ODB or SQLite or MySQL or MSSQL or whatever SQL-speaking database you wanted to.
        I hadn't thought yet about going the other direction!
        But either option feels pretty far away to me right at this moment. I'll definitely keep it in mind though.
        (I think but don't remember for sure that ChatGPT and I discussed this idea and wrote it up in my TODO_future_improvements.md. Nope. It's not there.)
    BTW: Here are a couple of links I mentioned to Dave on Wed
      Docserver text export that my (Claude-based) UserTalk Programmer agent references: docs/usertalk/docserver/
      The actual tests that are in the OPML file that I shared on Wed evening: tests/integration/test_cases/
    Tonight's adventure
      Lots of errands today, so only light work on code so far, but here's the meaty work for this evening's session:
      The outline in-memory management in the runtime is still using the push/pop antipattern for setting up op context. This has to go!
        It was a huge source of problems in the 64-bit database migration adventure!
        We have an established pattern for how to deal with this for odbs, for tables, and for wptexts. Outlines are the next target.
        Why this came up now
          I was working on implementing db verbs in parallel (coincidentally) with op verbs.
          The op work was progressing well until I ran into a separate issue (see below)...
          The automatic migration of v6 Guest Databases to v7 (64-bit) format was failing because it kept getting hinked up on outlines.
          A deep dive revealed that the push/pop pattern was the most likely culpret.
          We already had an issue about eliminating this pattern everywhere, so we're hitting the op instance of it now, to clear the way to complete both op and db verbs.
      The other gotcha for outlines: refcon data isn't 64-bit yet!
        I learned that the migration code doesn't widen data inside op refcons from 32-bit to 64-bit. A new unit test revealed this.
        So now I'm in parallel with the above, also doing a deep dive on refcons to make sure that the data they contain is widened to 64-bits just like all of the other odb data.
        I think this will be fairly straightforward, as again, I already have an established pattern to follow. It's mostly mechanical.
        And because I'm a good boy and my parents love me, I've got a swarm of AI agents who excel at mechanical work. 😜
      Plan for eliminating push/pop pattern for outlines: ADR-006-outline-push-pop-elimination.md
      Refcon 64-bit compliance update plan: V7_64BIT_VALUE_PACKING_PLAN.md
    Guest Databases plan in two phases
      Phase 1 - Goal: Make it easy to develop and test
        Legacy v6 roots keep .root extension and are never modified
        Migrated v7 roots use a .root7 extension (which would of course break UserTalk apps)
        System root: Currently in the repo as Frontier-v6.root with migrated v7 version moving to Frontier.root7
      Phase 2 - Goal: When stable, move to a more production-aligned approach
        New roots (v7) start using .root extension to make sure UserTalk apps continue to work post-migration
        Migration is automatic, but unlike older versions of Frontier, keep a backup
        v6 backup roots are renamed to Frontier.root.v6.bkp (bkp extension makes it easy to ignore in .gitignore)
      This gives us a clear way to keep track of which file is what version while in development, and ensures UserTalk apps work without modification once the low-level work is done. (No breakage!)
    Nearing completion of the op verb implementation (done)
      Done and tested:
        Phase 1: op.insert, op.getLineText, op.level, op.go, op.firstSummit, op.countSubs, op.countSummits, op.expand, op.collapse
        Phase 2, part 1: op.subsExpanded, op.promote, op.demote, op.deleteLine
        Phase 2, part 2: op.setLineText, op.deleteSubs, and op.reorg, but NOT op.find (which requires text editing / GUI)
      In progress:
        Phase 3: state management - cursor, refcon, hoisting/dehoisting
  January 7
    Dave: Integration tests as OPML -- all of them!
      https://raw.githubusercontent.com/jsavin/Frontier/develop/reports/integration_tests.opml
      This is a big file at 156K right now. Drummer handled it, but loading it up took a few seconds.
      When integration tests are added or modified, this file will be automatically updated via a pre-commit hook.
      Tail-end of the Claude Code conversation about this work: (just for fun)
        Claude: Here's the URL for Dave to subscribe to:
          https://raw.githubusercontent.com/jsavin/Frontier/develop/reports/integration_tests.opml
        Claude: This raw GitHub URL points to the OPML file and will automatically update whenever:
          1. You commit changes to any integration test YAML files
          2. The pre-commit hook regenerates the OPML
          3. The changes are pushed to develop
          Dave can add this URL to his OPML subscription tool and he'll always see the latest test structure in outline format - exactly as discussed! 🎉
        Me: Thanks! (Now if only GitHub supported OPML pub/sub.)
          Ha! Yeah, that would be amazing. GitHub could add an RSS/OPML feed per file with ?subscribe=true or something. Though I suppose the raw file URL works - Dave's tool just has to poll it periodically rather than getting push notifications.
          At least with the pre-commit hook, the OPML is guaranteed to be in sync with the test files whenever they're committed. No manual "remember to regenerate" step needed.
          Enjoy showing Dave the test suite in proper outline format! 340 tests with no curly braces or semicolons - just the way outline culture likes it. 😊
    O.M.G. Claude just told me a thing that I heard from a 25-year Microsoft veteran early in my career
      I've carried this mantra forward ever since I first heard it: "First understand reality, then adjust the plan to match reality."
      It's so obvious that nobody ever says it!
      Claude Code just offered as a next step in implementing op verbs to "update the plan to match reality".
      Again this is super obvious, but the similarity to my visceral memory of a specific experience really took me back!
  January 6
    Corner turn after dinner and a movie this evening: Guest Databases
      The AI doesn't understand how these work yet, so the first step is to discuss and document the right behavior.
      After that make a test-driven implementation plan (write tests first, and iterate 'till they all pass)
      Then code reviews. (This might take more than one session depending on complexity.)
      (Working in parallel on op verb implementations.)
    Lang and file verbs are now 100% complete.
      Now working on op.*
      I have an appointment this afternoon and need to prep for an interview tomorrow, so it may be a light day overall.
  January 5
    Repo hygeine work today: deleted many stale branches
      Started the day with 87 branches, now there are 3, including develop. (Deleted 78 stale branches.)
      Direct deletion - 71 branches
        Low-risk branches (docs/, chore/, etc.) - 13
        Merged feature/fix branches - 44
        Zombie branches (squash-merged PRs) - 6
        Stale November branches (2+ months old) - 3
        Stash snapshot branches - 1
        Remote zombie branches - 2
        Archive stash snapshots (carbon-migration, portable-refactoring) - 2
      Code-reviewed branches - 7 (reviewed by Code Review Agent)
        feature/batch1-stateless-verbs - Superseded by PR #181
        feature/issues-171-159-167 - Build failures, work superseded
        fix/lang-new-segfault - Merged via PR #200 + follow-up
        feature/phase2-headless-outline-ops - Superseded by PR #210
        fix/test-infrastructure-hdlintarray - WIP, better version in PR #217
        feature/file-verbs-debug - Architectural mistake (typeof()), extracted docs
        feature/verb-bindings-quick-wins - Superseded by PR #241
  January 3
    Saturday evening session
      Current task: Finish up real implementations of file verbs, along with integration tests - DONE
        I'm on the last round of this now. There's only one thing I know of that won't work (easily) file.mountServerVolume()
          In POSIX systems like macOS and Linux this requires either an key-based auth or elevated priveleges.
          I'll come back to this later... maybe. (It's not important at the moment.)
          Right now this verb will trigger a scriptError: "Can mount server volume because it's not implemented on this platform.")
            This is the same pattern we used for Mac-isms that don't work on Windows.
        https://github.com/jsavin/Frontier/pull/241
      Filed a P1 bug to deal with the cross-platform line endings issue that plagued us in the mixed Mac and Windows world.
        The idea is to auto-detect line endings when possible, and choose a sensible platform default, with optional params to override.
        Here's the issue: https://github.com/jsavin/Frontier/issues/240
      Because we have basically no users any more (that I know of) besides me and Dave, this is a great time to deal with tech debt!
    Today is going to be a lighter day.
      Chores to do. Maybe I'll get some more serious work done this evening when it's quiet.
      Dave: Thanks for noticing the programming lessons. 😃
    Task at hand
      Bindings for the rest of the headless-capable verbs
        Bind in groups -- turns out this was also ahead of where we thought!
          The static analyzer was looking for implementations not end-to-end bindings. 🙁
            Basically we were validating that the C code was working, portable, etc -- but not whether any of it worked in UserTalk!
            This was a surprise to me, but shouldn't have been. My unit test framework is implemented in C, but UserTalk doesn't run in C!
            I knew this was coming but not how big it was. I thought we were 60% of the way there, but it's more like 25%.
            The Good News™: The C-level unit tests give a really solid foundation for ensuring that the runtime will work well.
            The Bad News™: Now I need real integration tests. (Done -- see above!)
            I also fixed the static analyzer to give a more truthful answer.
              As a senior engineering manager at Microsoft once told me: "First understand reality, then adjust the plan to meet reality."
          Quick Wins - Nearly complete processors with 1-5 verbs each
            clock (85%) - 1 verb
            date (86%) - 4 verbs
            file (96%) - 3 verbs
            op (97%) - 1 verb
            html (95%) - 1 verb
            xml (92%) - 1 verb
            menu (85%) - 2 verbs
          Already [mostly] done 🎉
            table (100%)
            sys (93%) - 1 verb
            string (60 verbs) - core language operations
            file (86 verbs) - file I/O
            db (13 verbs) - database operations
            frontier, mysql, sqlite, crypt, kb, math, mainwindow, opattributes, pict, point, rectangle, rgb, speaker, mouse (many are stubbed)
        Write unit tests and integration tests
          We need to audit the unit tests to make sure we're covering all the newly bound verbs.
          Integration tests using frontier-cli to validate UserTalk is still a little far away. We will need a long-running process first.
        PR once tests pass
        New learning on 12/29
          Apparently the headless build was missing or had broken implementations of a lot of bindings already!
            This is a fundamental disadvantage of using AI agents: They sometimes do partial work and don't remember ever having done it!
          Right now working through these. It's going to be a slog for a day or three.
  January 2
    Dave: Congrats on your Edit milestone!
    Today's important milestones for me
      Refactored the way that parameters are passed in to UserTalk kernel implementations to make them thread-safe
        There was a collection of global variables that were managed by the UserTalk thread management system. (I don't know specifics.)
        Claude identified in a code review whlie working on file verbs that this wasn't thread-safe from the POV of modern OS-managed threading systems, and was likely to cause bugs.
        We refactored these to be passed into the UserTalk thread context as thread-globals which makes them inherently thread-safe.
        This eliminates another class of globals that the kernel was juggling. When we get to 100% with that, the runtime should be fully thread-safe on modern systems, and can be refactored to leverage OS-level preemptive multi-tasking, multi-core processors, etc.
        My CLAUDE.md has a section about global mutable state which says at the top BURN THE GLOBALS WITH FIRE. EVERYWHERE.
          Claude was actually quoting me verbatim when it added that! 🤣
      Fixed some 32-bit datetimes that were missed in the previous round
        The WPText runtime was still using longs for datetimes, which will break around 2039. There was at least one other.
        Fixed the existing issues, and added a script which runs along with my automated tests to catch if this pattern ever reappears.
          Why would it reappear? A couple of reasons:
            Bringing in an implementation file or header that wasn't previously included in my makefile
            An AI model halucinates that it should be a lon or [u]int32_t instead of unit64_t (which is what frontier_datetime_t is defined as)
            An unrelated previous change has to be reverted, regressing a previous fix
      Now completing the file verbs
        Claude did something dumb a few minutes ago. It tried to change the return value of typeOf() from a string4 to a string.
        This would have broken EVERYTHING.
        I immediately explained why this can't be done, and asked it to write some guidance for itself so it won't happen again.
        Why did it do that? A test was failing because the test was written to expect `typeOf(f) == "filespec"` and then it incorrectly assumed the bug was in typeOf and not in the test. Oy!
        Very glad I caught it quickly!
  January 1
    Consolidated my AI-assisted programming tips in a new outline
      https://drummer.land/me@jakesav.in/TipsForAIProgramming.opml
        Collecting stuff I've learned here
        Tips
          All three of OpenAI (codex-cli), Claude (claude-code), and Gemini (gemini-code) have CLI orchestration tools that can work with local files and anything you can do in the terminal.
            You can also ask them if there are other development tools that they need and how to install them, or even ask them to install for you.
            I'm working in a somewhat unsafe fashion as I've given the tools complete access to my Frontier project, plus authorized them to do stuff without stopping and asking me for permission (seemingly) every minute or more.
          I'm mostly getting the best results from Claude Code at the moment, now that I've upgraded to the $200/month plan.
            It seems to be worth it, at least to me!
          Let me know if you'd like any tips on using claude-code or codex-cli. Here are a few:
            Make it easy for them to test
              Ask them to help design a test framework and make sure they run tests every time something significant changes.
              Make sure to document the test runner command(s) so that the agents can run them without having to read code first.
            Spend time in "planning" mode before asking them to make any big changes
              The agents can only remember so much at one time and don't *really* understand architecture. They have to relearn stuff every session.
              My solution to this was to have them create and continually maintain documentation about my project in a structured sub-directory.
              When a planning doc is no longer relevant (work is done or deferred), have them move it to a separate archive folder to reduce noise.
              You can also use "#" at the start of a prompt in claude-code to create memories, kind of like ChatGPT memories. These are injected at the top of every session.
            In claude-code sub-agents are your friends!
              You can type /agents in claude-code to create and edit agents. These can be experts in whatever you want.
              Agents are defined in human-readable format in text files under .claude/.agents in your home directory (for global ones) or in your project directory (for project-specific ones).
              By asking Claude to use sub-agents as needed in your prompt you save a *lot* of context in your main work area so it can remember more.
            Use the smaller models for mundane tasks
              Writing simple docs or todo lists
              Working with git / GitHub (you have to tell them that they're allowed to do this if you want them to use the "gh" command)
              Running or maintaining tests
              Asking questions about code or about work done
            Use the bigger models for anything complex
              Sonnet is my goto in claude-code. Haven't needed Opus yet
          Tip: The Claude macOS app can also talk to some applications: Notes, Mail, Google Calendar, BBEdit, Terminal, and some others
          Tip: The ChatGPT macOS app can also talk to Terminal and some others, but not as extensive a set as Claude
          Tip: Claude Code has some "self-awareness" of each model's capabilities. If you don't know which model to use for a given chunk of work, ask it whether you should use Haiku (lightest) or Sonnet. (I've never had to use Opus and it will use your quota really fast.)
          Tip: I just learned that Claude Code's model was trained using XML tags to indicate what part of a prompt is what kind of thing, and that you'll get better results from Claude (and Claude Code) if you prompt like this:
            https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/use-xml-tags#why-use-xml-tags
            Example
              What you want Claude to do
              Background information it needs
              Any limits or rules
              How you want the answer
            You can use whatever tag names make the most sense for you or your task and Claude should be able to figure out your intent.
            Note: I haven't tried this yet. I've been using structured Markdown documents for similar things though.
        AI agents on CLI
          All three of OpenAI (codex-cli), Claude (claude-code), and Gemini (gemini-code) have CLI orchestration tools that can work with local files and anything you can do in the terminal.
            You can also ask them if there are other development tools that they need and how to install them, or even ask them to install for you.
            I'm working in a somewhat unsafe fashion as I've given the tools complete access to my Frontier project, plus authorized them to do stuff without stopping and asking me for permission (seemingly) every minute or more.
          I'm mostly getting the best results from Claude Code at the moment, now that I've upgraded to the $200/month plan.
            It seems to be worth it, at least to me!
          Let me know if you'd like any tips on using claude-code or codex-cli. Here are a few:
            Make it easy for them to test
              Ask them to help design a test framework and make sure they run tests every time something significant changes.
              Make sure to document the test runner command(s) so that the agents can run them without having to read code first.
            Spend time in "planning" mode before asking them to make any big changes
              The agents can only remember so much at one time and don't *really* understand architecture. They have to relearn stuff every session.
              My solution to this was to have them create and continually maintain documentation about my project in a structured sub-directory.
              When a planning doc is no longer relevant (work is done or deferred), have them move it to a separate archive folder to reduce noise.
              You can also use "#" at the start of a prompt in claude-code to create memories, kind of like ChatGPT memories. These are injected at the top of every session.
            In claude-code sub-agents are your friends!
              You can type /agents in claude-code to create and edit agents. These can be experts in whatever you want.
              Agents are defined in human-readable format in text files under .claude/.agents in your home directory (for global ones) or in your project directory (for project-specific ones).
              By asking Claude to use sub-agents as needed in your prompt you save a *lot* of context in your main work area so it can remember more.
            Use the smaller models for mundane tasks
              Writing simple docs or todo lists
              Working with git / GitHub (you have to tell them that they're allowed to do this if you want them to use the "gh" command)
              Running or maintaining tests
              Asking questions about code or about work done
            Use the bigger models for anything complex
              Sonnet is my goto in claude-code. Haven't needed Opus yet
          Tip: The Claude macOS app can also talk to some applications: Notes, Mail, Google Calendar, BBEdit, Terminal, and some others
          Tip: The ChatGPT macOS app can also talk to Terminal and some others, but not as extensive a set as Claude
          Tip: Claude Code has some "self-awareness" of each model's capabilities. If you don't know which model to use for a given chunk of work, ask it whether you should use Haiku (lightest) or Sonnet. (I've never had to use Opus and it will use your quota really fast.)
          Tip: I just learned that Claude Code's model was trained using XML tags to indicate what part of a prompt is what kind of thing, and that you'll get better results from Claude (and Claude Code) if you prompt like this:
            https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/use-xml-tags#why-use-xml-tags
            Example
              What you want Claude to do
              Background information it needs
              Any limits or rules
              How you want the answer
            You can use whatever tag names make the most sense for you or your task and Claude should be able to figure out your intent.
            Note: I haven't tried this yet. I've been using structured Markdown documents for similar things though.
        Claude Code is even more incredible than I thought
          Here's what I just did...
            In the middle of the push/pop → explicit database context refactor project I've been talking about, I had an idea about a simpler way to do this. The details aren't important but what I did with Claude Code just kinda blew my mind.
            When I had the idea, I interrupted the work in progress to ask it whether my new approach would be easier/better.
            Claude decided to ask the system-architect sub-agent (that I'd created) which thought for 2 minutes and made a recommendation, part of which was to create a new document describing how it would work.
              1. Stick with the current work: we're on the right track
              2. Add some helper functions to make it easier to understand
              3. Create a document explaining the idea and how it could be implemented
            So I asked Claude to tell the architect agent to work on the doc, and I would move it to a background task so we could keep working on the refactor...
            And what did Claude do? It asked the architect to work on the doc in the background, and then got right back to work on the refactor.
            This could be incredibly powerful! I could imagine doing multiple things in the background while I'm focusing on the task at hand, and then when I'm done I'd be all set up to go right into the next workstream.
          It feels like a magic trick! 🪄 🎩 🐇
            This would be an even more powerful magic trick:
              Sub-agents that automatically learn over time.
              https://claude.ai/share/7e582fc5-5850-4263-9852-0500c0f242ca
              Claude Code doesn't have this yet.
    Work done or in-progress today
      Verb implementations and bindings
        file verbs (~50%)
          Turns out that file.getPath(), which is supposed to return the current working directory, was returning the wrong directory on Windows, and file.getFilePath() which should return the path to Frontier.root IIRC, didn't work at all!
          I'm fixing these. We're going to have real thread-safe working directories, and POSIX-compliant behavior.
          We never noticed these issues at UserLand because all of our code that needed to find stuff in the Frontier folder used frontier.getProgramPath() instead, which worked!
        table verbs (100%)
        string verbs (100%)
        All verbs have both C-level unit tests and UserTalk integration tests (enabled by the new test runner from yesterday) and are 100% passing
      New doc for interactive mode when using headless in a terminal (with a flag to turn it off)
      Up next for my evening session after a meal and some TV
        Finish file verbs -- still in progress
        Wire up op, script, and wptext verbs
    Thinking again about user interactions in headless
      The AI told me today that the standard Unix pattern is to default to interactive mode if running in a TTY (terminal) and have a command-line flag to override this behavior and run non-interactively.
        I was already thinking a little along these lines a few weeks back, and Dave reminded me that there might be problems with an interactive mode, especially if we were to change our minds later and take it away.
      What I'm going to do now:
        1. Make any verb that triggers a user interaction trigger a scriptError saying that it's not supported in headless.
        2. Have my system architect agent write a planning doc for what terminal interactive mode would look like and assess difficulty.
        3. Ensure that if headless is running as a daemon process it always triggers errors when a script tries to interact with the user.
        tl;dr: No interactivity yet, but the ground will be ready for it if I decide to plant the seed.
2025
  December 2025
    December 31
      Happy New Year! 🎊
        Hope you all are well, and best wishes for 2026!
        PS. Sorry about your outage, Dave. 🫂
          Reminds me of the wind storm that took out power in the Seattle Area in Dec 2006 after we moved here.
          Our power was out for 9 days. We decided on day 4 to take an early Xmas vacation in Vancouver -- the nearest hotel vacancies.
          I knew when the power came back on because Frontier sent an email to me. 😉
      Completed today
        Resolved test crashes and cleaned up infrastructure
          PR #218: fix: Resolve test infrastructure issues - segfault and build failures
          PR #217: refactor: Eliminate redundant portable/frontier.h header
          PR #212: test-cleanup: Stabilize test infrastructure and fix headless runtime issues
          This was a tough one! almost 20 rounds of reviews and addressing feedback!
        Completed table verb implementations with unit tests
          PR #210: Table Navigation Verbs and error infra fix
          PR #205: headless table selection tracking infrastructure
          Note: Tables in headless support the same selection, target, and op.* navigation that the GUI version does.
            Built a thread-specific selection and target system to support these.
            (The target system was already there for op.* verbs, and now supports all externals.)
        Created an integration test framework for validating UserTalk bindings and behavior in the CLI runtime 🎉
          Just in time for the New Year, I can now create tests that verify runtime behavior from the UserTalk domain, not just the kernel.
          This is important because it unlocks rapid progress making sure the UserTalk runtime has functional parity, not just the kernel!
          It will enable me to quickly add/modify/validate both the existing verbs, and new ones. Onward Ho!
    December 29
      I got a little ahead of myself on 12/27 wrt multiple Claude instances
        It turns out it's even harder to manage a team of teams of AI agents than it is to manage a team of teams of humans!
          The challenge is about telling "who is who" more than managing the work, which I'm confident that I can do (with humans).
          I can't tell the difference. They don't have faces or voices. They all speak exactly the same way.
          That makes it really hard for *me* to keep their context in *my* head.
        I think tmux might be a solution for this.
          It's a command line program for managing multiple terminal sessions.
          It can keep a session alive even if your terminal app dies or you're on a flaky ssh connection.
          Most importantly, you can give sessions names!
          And you can view multiple sessions in one window - sort of a text-based windowing system.
            Remembering the Apple II and PC apps of the '80's!
      Today's digression: segfault bugs
        There were two: one triggered by lang.new() and a collection with the same root cause related to table migration tests.
          In the end the lang.new() one turned out to be yet another push/pop antipattern issue which we addressed with a single-decision-point pattern.
            The other one was easier: I cleaned up a bunch of timenow() calls (32-bit), replacing them with timenow64() for obvious reasons, but there was a source file missing from my makefile so we had the definitions but not the implementations.
        Now that those are both fixed I'm working again on the table verbs, and because tables are outlines, also op verbs.
          I had designed headless-safe versions of the target and selection systems that will work against underlying data in headless instead of with data associated with a window. (Headless has no windows, but selections and targets need to continue working!)
          The target system was already implemented last week.
          The new addition today is the selection tracking system. That's in progress.
        Peeling back the onion further revealed that verb dispatch has been broken for a while (days)
          My test cases didn't cover this broadly enough, and I was over-reliant on specific tests when merging code updates.
          Lessons learned: 1) Run ALL TESTS every time I push a change. 2) Ensure test cases fully cover all critical paths!
            This is what I'm working on now until I have a yellow brick road ahead.
        When this work is done after this digression (in 5 phases), we'll have 100% of the table verbs and most or all of op verbs working.
    December 27
      I've figured out how to work with multiple instances of Claude Code in parallel
        Git worktrees was the unlock: I just ask the Nth agent to create a new worktree based on develop, and it can work independently without interfering with the N-1 agent.
          This is going to be interesting. Now I really have to stay on top of my work tracking with so many things going on at once!
        Right now working on 1) bindings for table verbs, 2) investigating the 1 remaining sys verb, and 3) fixing high-priority bugs.
    December 25
      Merry Christmas!
      Dave: You might get a kick out of this
        I created a UserTalk agent. It knows how to code in UserTalk. (Did a few small tests and it worked!)
        https://github.com/jsavin/Frontier/blob/develop/.claude/agents/usertalk-engineer.md
        To your question about running your script that builds your JavaScript stuff, I'm not there yet, but might be soon. Still connecting the odb to the kernel at the moment, but it's a *lot* more stable than it was a couple of days ago.
          This agent can write UserTalk code using Claude (in the cloud), but I can't run all the code it generates just yet.
    December 24
      Crazy -- I don't even have to create sub-agents myself: I just ask Claude to do it for me!
        My prompt: "Can you go ahead and create a project-level thread-safety-expert agent that uses Sonnet, and is tuned to the requirements of this project? Please also create a test coverage analyst that uses Haiku, and a documentation specialist that also uses Haiku. (I need to marinate a bit on performance/profiling.)"
      A handy PR-bot helper tool
        I made a little script that monitors a PR for feedback from the Claude PR Review Bot (which triggers from a GitHub workflow).
        After pushing a PR, I trigger the tool and it will wait up to 10 minutes for the bot to give feedback.
        If there are important bugs, Claude Code will fix whatever issues are called out and update the PR without my doing a thing.
        All I had to do to make this work was add a list item in CLAUDE.md to remind it that it exists, and to run it after pushing a PR!
      Jumped another big hurdle on the database migration
        The refactor I finished yesterday to move from a push/pop db context model to a deterministic one revealed new bugs.
          1) The menu packer was incomplete -- menu scripts were still stubbed, so test validations failed
          2) The pictType migration had a segfault (those are straight binary copies with new headers)
        Fixing the menu packer issue required testing implemented via cli using frontier-cli directly instead of the test shim.
          It needed access to all the built-in stuff in order to write test scripts in UserTalk.
          A key verb, new() hadn't been bound yet, so we had to fix that in order to get tests to complete.
        Good news: After this corner-turn, the full test suite is 100% passing, and I should be able to get back to verb implementations now!
          But first I have to do some house-keeping: put up a PR for the bot to review, merge, and re-test on develop (the main branch).
        Over all, the work took Claude about 6 or 7 hours to complete in *many* separate "phases", depending on each other in sequence.
          My system-architect sub-agent really shined on this one!
    December 23
      Dave: Congrats on the interop milestone with Inoreader! 🙂
        Also a reminder that I shared some advice on cli-based coding AI agents here:
        https://drummer.land/me@jakesav.in/JakeShare.opml?permalink=20251123001239
      Claude Code is even more incredible than I thought
        Here's what I just did...
          In the middle of the push/pop → explicit database context refactor project I've been talking about, I had an idea about a simpler way to do this. The details aren't important but what I did with Claude Code just kinda blew my mind.
          When I had the idea, I interrupted the work in progress to ask it whether my new approach would be easier/better.
          Claude decided to ask the system-architect sub-agent (that I'd created) which thought for 2 minutes and made a recommendation, part of which was to create a new document describing how it would work.
            1. Stick with the current work: we're on the right track
            2. Add some helper functions to make it easier to understand
            3. Create a document explaining the idea and how it could be implemented
          So I asked Claude to tell the architect agent to work on the doc, and I would move it to a background task so we could keep working on the refactor...
          And what did Claude do? It asked the architect to work on the doc in the background, and then got right back to work on the refactor.
          This could be incredibly powerful! I could imagine doing multiple things in the background while I'm focusing on the task at hand, and then when I'm done I'd be all set up to go right into the next workstream.
        It feels like a magic trick! 🪄 🎩 🐇
          This would be an even more powerful magic trick:
            Sub-agents that automatically learn over time.
            https://claude.ai/share/7e582fc5-5850-4263-9852-0500c0f242ca
            Claude Code doesn't have this yet.
        Push/pop refactoring work continues
          When this is done, database operations will be fully (modern) thread-safe, and migrations to the new format will be much more stable.
            Also planning some refactoring to optimize memory usage during migration so that really large databases don't have to be fully loaded into RAM before converting, and instead they will be converted "on the fly" one external at a time.
            Latest update from the bot on this as of about 11pm:
              Completed Refactorings (7 major fixes)
              1. Mode Stack Corruption Fix (77ea2c33)
                - Fixed critical bug where v6 mode was copied to v7 destination
                - Added g_mode_depth = 0 before applying v7 mode to prevent stack override
              2. External Materialization (77ea2c33, 3cfaf238)
                - Tables, outlines, scripts, wptext all now materialized correctly
                - Scripts identified as outlines with flscript=true flag
              3. Picture External Refactoring (89621aaf)
                - pictverbinmemory() - explicit context parameter
                - pictverbpack_internal() - new _internal function
                - Fixed recursion bug: only recurse into table externals
              4. LangExternal Pack Mode Fix (b815ec0c)
                - Fixed critical bug: v7 write mode now set for ALL externals during migration
                - Previously only set when loading from disk, not for pre-materialized externals
              5. WPText DBRef Refactoring (08e147e1)
                - Removed push/pop from wp_portable_state_dbref()
                - Now uses explicit db_context parameter
              📊 Current Status
                - ✅ Mode stack depth correctly managed
                - ✅ External materialization working for all types
                - ✅ Context threading in place for pictures, outlines, wptext
                - ⚠️ 22 remaining dbpushdatabase calls need refactoring
            Phase 2 Results
              91% reduction in dbpushdatabase calls (from 22 → 2 remaining)
              3 of 4 deferred files successfully refactored (dbstats.c deferred as low priority)
              3 helper functions created following ADR-002 patterns [this is the doc that the system-architect agent created]
              All tests passing, deterministic migration maintained
            Planning docs are on a branch here while working on this.
          Done!
            Deleing dbpushdatabase and dbpopdatabase from the code now, and will then run tests and do a PR! 🎉
            https://github.com/jsavin/Frontier/pull/161
      Logging system is now migrated to code instead of compiler directives
        We can now use tell frontier-cli what log level to use, and optionally what level for given sub-systems.
        This will be a big help to the AI agents since they won't have to modify source files any more to trigger logging, and will be able to drill into the specific component(s) they're working in.
        I decided to do this first before digging further into the push/pop anti-pattern. That'll be next.
    December 22
      Push/pop anti-pattern reappears, this time in hashpackexternal() when migrating tables
        My system-architect sub-agent was able to suss it out and make a relatively straightforward refactoring plan to fix it.
          The fix is to explicitly pass database context through hashpackexternal() instead of relying on a global db variable and maintaining temporary states on that variable. (Memory is essentially free now!)
          Fortunately we caught this quickly and only one of my ~50 tests was failing.
          Fingers crossed that the fix will be easy. (The first one of these took days.)
        The fix is progress but it didn't work – dig we must!
          Now we need to make sure that contexts being passed to hashpacktable_internal during migration actually have the correct format attribute. (It's still writing them using the v6 table packer!)
      Scott: Docker
        I've used Docker quite a bit on my Synology NAS. It's got a pretty nice web-based GUI for managing images and containers, and setting up environment variables and networking.
        I haven't worked with docker compose much yet, but ChatGPT and Claude know all about it and can help you.
      AI agents on CLI (Dave note)
        All three of OpenAI (codex-cli), Claude (claude-code), and Gemini (gemini-code) have CLI orchestration tools that can work with local files and anything you can do in the terminal.
          You can also ask them if there are other development tools that they need and how to install them, or even ask them to install for you.
          I'm working in a somewhat unsafe fashion as I've given the tools complete access to my Frontier project, plus authorized them to do stuff without stopping and asking me for permission (seemingly) every minute or more.
        I'm mostly getting the best results from Claude Code at the moment, now that I've upgraded to the $200/month plan.
          It seems to be worth it, at least to me!
        Let me know if you'd like any tips on using claude-code or codex-cli. Here are a few:
          Make it easy for them to test
            Ask them to help design a test framework and make sure they run tests every time something significant changes.
            Make sure to document the test runner command(s) so that the agents can run them without having to read code first.
          Spend time in "planning" mode before asking them to make any big changes
            The agents can only remember so much at one time and don't *really* understand architecture. They have to relearn stuff every session.
            My solution to this was to have them create and continually maintain documentation about my project in a structured sub-directory.
            When a planning doc is no longer relevant (work is done or deferred), have them move it to a separate archive folder to reduce noise.
            You can also use "#" at the start of a prompt in claude-code to create memories, kind of like ChatGPT memories. These are injected at the top of every session.
          In claude-code sub-agents are your friends!
            You can type /agents in claude-code to create and edit agents. These can be experts in whatever you want.
            Agents are defined in human-readable format in text files under .claude/.agents in your home directory (for global ones) or in your project directory (for project-specific ones).
            By asking Claude to use sub-agents as needed in your prompt you save a *lot* of context in your main work area so it can remember more.
          Use the smaller models for mundane tasks
            Writing simple docs or todo lists
            Working with git / GitHub (you have to tell them that they're allowed to do this if you want them to use the "gh" command)
            Running or maintaining tests
            Asking questions about code or about work done
          Use the bigger models for anything complex
            Sonnet is my goto in claude-code. Haven't needed Opus yet
        Tip: The Claude macOS app can also talk to some applications: Notes, Mail, Google Calendar, BBEdit, Terminal, and some others
        Tip: The ChatGPT macOS app can also talk to Terminal and some others, but not as extensive a set as Claude
        Tip: Claude Code has some "self-awareness" of each model's capabilities. If you don't know which model to use for a given chunk of work, ask it whether you should use Haiku (lightest) or Sonnet. (I've never had to use Opus and it will use your quota really fast.)
        Tip: I just learned that Claude Code's model was trained using XML tags to indicate what part of a prompt is what kind of thing, and that you'll get better results from Claude (and Claude Code) if you prompt like this:
          https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/use-xml-tags#why-use-xml-tags
          Example
            What you want Claude to do
            Background information it needs
            Any limits or rules
            How you want the answer
          You can use whatever tag names make the most sense for you or your task and Claude should be able to figure out your intent.
          Note: I haven't tried this yet. I've been using structured Markdown documents for similar things though.
      Push/pop anti-pattern
        I see the runtime doing this pattern a lot
          Push some external object, do an operation on it, pop it.
        The problem is that the state management is done with globals. This means that it's not thread-safe on modern systems.
          I filed two P1 issues, one specifically for op objects, and one to audit the code for this anti-pattern and make a plan to address them.
        After this is resolved it will be possible to look again at modernizing the runtime's thread management system.
          The idea here is to make everything truly thread-safe with no or minimal use of globals across the runtime.
          Then I'd be able to make the runtime take advantage of system kernel-level thread management.
          This would be a big win in terms of stability, memory management, and potentially performance.
    December 21
      Yesterday's milestone
        In last night's session I finally got to the summit on the v6 → v7 database migration.
          The core issue was that it was using a push/pop stack to keep track of which database format it was unpacking/packing, but the inherently recurisve operation of migrating the database was causing that to be extremely fragile, and the AI was having a horrible time debugging it.
          After repeated attempts at simpler, more targeted fixes, I finally decided to fix it once and for all.
          Now throughout the read/unpack and write/pack code, the database context is passed explicitly so that the packer/unpacker know what to do definitively via stack-based management instead of the poorly designed global push/pop system.
          All the tests are passing, and we also created new v7 database validation tests, which also pass.
      Doing some housekeeping this evening
        The AI agents are spending a lot of tokens rifling through old, obselete code.
          This is an antipattern here because 1) it's more expensive, 2) the agents have context window limits, and 3) it can cause them to make mistakes.
        There are a ton of old #define's and blocks of code in #ifdef blocks marked things like OBSOLETE or NEVER.
          These can all go.
        Using a collection of commonly available static analysis command-line tools, Claude Code also identified a lot of code that's dead.
          Have to be a bit more careful here because there may be false-positives, but a lot of dead code can go too.
          Might want to wait to do this until after wiring up most of the verbs though!
        Also going to clean up a bunch of logging and introduce log-levels at runtime instead of as compiler directives.
          This will enable me (and the test runner and agents) to enable/disable more verbose logging just for the components actively being worked on, and will also save a lot of tokens. (Cheaper, faster, more accurate agent-assist and better understanding.)
          Runtime console logging design enables 5 log verbosity levels, and can be set per component or globally.
          Output is both plain-text to stdout and JSON to stderr. JSON is useful for AI agents, or other machine reading apps/tools.
          Long-term we'll add new verbs to get and set log levels, so I filed a GitHub issue for that.
    December 20
      Brent: Where's your outline?
    December 18
      Out today. Visiting my mom in Olympia.
        I'll be spotty the next couple of days.
    December 17
      Reflections on the first big milestone for Headless Frontier (frontier-cli)
        Requirements:
          It should run UserTalk scripts
          It should make all of the CLI-compatible verbs work (i.e. anything that doesn't require a GUI or window system)
          It should be able to be run as a long-running process that you can send messages to, which run UserTalk scripts
          It should persist data in ODBs (.root files) on disk
          It should have an HTTP client and web server which work in the UserTalk domain
        That's it! That's the first milestone (which my project is currently calling "Phase 3").
          Phase 1 was a planning phase.
          Phase 2 was all about the 64-bit port: getting headless to a minimally-working state, automated tests, and low-level database stuff.
          Phase 3 is the first usable deliverable, and is the current work-in-progress.
      Fixed the database migration bug – finally!
        This was a particularly difficult one to track down.
        The PR notes explain the details in case anyone is interested:
        https://github.com/jsavin/Frontier/pull/117
        tl;dr: The bot (and therefore the code) were confused about which addresses referenced the legacy v6 root, and which ones referenced the migrated v7 root with the new ~modern~ big-endian 64-bit format.
        Now that this is fixed I'm almost ready to turn back to verb enablement, but first I'm going to figure out how to prevent similar regressions from ever happening again.
        This is complex code that's not easy to mentally model for a human, and the AI agents – while very good at common, simple algorithms and syntax, are not good at complex mental models! (This is the biggest thing I've learned from this project actually!)
      Still diggin' (done!)
        ...out of the hole I got myself into with database migration. Turns out that unpacking externals from disk wasn't working.
        Now working off of a detailed plan for debugging this, starting with console logs to confirm/refute theorized root cause.
    December 16
      Up next
        Generate a prioritized backlog of the next block of verbs to implement. ✅
        Implement table verbs
          Turns out that new (tableType, @t) isn't working.
          I'm guessing that new isn't wired up yet!
      Clock and Date verbs are in
        Also fixed a bug in table storage of 64-bit datetimes for timecreated and timemodified.
    December 15
      Switching back to the C/kernel domain today, leveraging the analysis work done yesterday to drive bindings for a large set of verbs.
        Work will be in short bursts. I've got a lot of unrelated stuff going on today.
        Just merged a simple change to test the approach: Bindings for sys.getEnvironmentVariable and sys.setEnvironmentVariable (which Brent had added way back when he did the OS X port).
        Now working on clock.* and date.*.
    December 14
      Progress on verb binding work
        Just merged a PR which implements a static C code analyzer that will be instrumental in getting lots of verb bindings wired up quickly:
          https://github.com/jsavin/Frontier/pull/104
          tl;dr: This PR introduces a static analysis framework in Python that detects implemented kernel verbs without modifying C source code, in preparation for follow-up phases.
            Phase 2: Dry-Run & Verification
            Phase 3: Test Infrastructure
            Phase 4: Migration & Documentation
          You can see the report on GitHub here: reports/coverate/verb-binding/2025-12-14-02.md
          Summary below (56% of verbs implementations detected)
            Processors detected: 27/51
            Implemented verbs detected: 400/707 (56%)
            Processors at or near 100%: clock, date, db, frontier, html, lang (minus OSA/AppleScript), math, menu (minus GUI hooks), op, point, rectangle, rgb, string, sys, xml
            15 processors of 51 total
      Dave: Regarding dialog.alert, I completely hear you.
        It's important to not paint myself into a corner where I either break existing stuff or have to indefinitely support something that's sub-par or not ideal.
        A possibility (and it would be easy) would be to have a command-line parameter that enables "interactive mode" for the headless app. I imagine it working something like this:
          > frontier --interactive⏎
          In this mode, msg(), dialogs, etc would use stdio to interact with the user.
          Without the --interactive flag, dialogs would error out.
        We could in parallel implement console verbs. (I think there's some stuff already there in system.verbs.builtins.sys, but I'd need to investigate.)
        I'll also have a chat with the AI about this. I'm guessing there are other similar tools out there so there may be prior art.
          Thinking about REPL's like JavaScript console, Swift, Python, etc.
    December 13
      Now that I'm back on track, I'm going to use this evening session to implement automatic verb registration.
        Claude and I are working on a doc:
          planning/phase3/kernel_verb_porting/automatic_verb_binding_architecture.md
        The core idea is to automatically wire up kernel-level verb implementations with the UserTalk glue.
        The approach is to extend a Python script that we already have so that it can inspect the C code and find functions that implement verbs, and then generate C code that does the bindings.
        We already had automatic generation from a resource file (.rc) in the legacy code base, but telling the generator which things were implemented was a manual process.
        Automating this will enable us to easily create new verbs, and will vastly reduce the effort needed to get most/all of the existing ones working.
      Finally dug myself out of the hole I managed to get into last night.
        I broke the UserTalk runtime when I asked Codex to fork the 64-bit reader/unpacker into its own set of "_modern" functions not realizing that the v5 and v6 code paths were also named "modern".
        Codex got very confused by this and broke things, but I didn't notice until a few PRs had been merged on this broken state because I wasn't running the full set of tests with each change.
        I've taught Codex and Claude to both always run tests whenever they've completed some work and before creating PRs.
        The fix for this actual issue turned out to be: 1) Fixing the legacy 32-bit reader/unpacker mess, 2) renaming my new code "_64" instead of "_modern" to avoid confusion, 3) removing the code that was automatically (supposed to do) binding of verb glue scripts (aka "processors") to their kernel implementations.
        Now I'm a couple of steps behind where I thought I was on Thursday, but at least the runtime is stable and the next steps are clear.
          1) Carefully wire up a few more verbs (again), starting with clock.*
          2) Make a plan for how to register *all* of the verbs that make kernel calls.
          3) Write a *lot* more tests to validate verb implementations.
    December 10
      This is frustrating
        This morning I was really close to pushing a PR with all of the system verb registration and bindings, and fixes for menubarType migrations to the modern format, and I made a big mistake: I didn't ask Codex to make a commit before starting logging cleanup work... And it broke everything trying to do that simple task. So now we have to fix it again. (Details in subs.)
          Asking it to revert the logging cleanup changes only made things worse.
          So after some personal stuff this afternoon and earlier this evening, I decided to revert to an earlier local commit.
          Now I need to coach it through the registration and menubarType migrations again.
          The good news: The documentation we wrote for that work still lives! And it should be straightforward to redo the work.
          I'm proceeding carefully here, and want to land this PR so we can start reviewing automated code review feedback and bug reports tomorrow.
        Lesson learned: ALWAYS DO A LOCAL COMMIT WHEN THE SYSTEM IS IN A GOOD STATE!
          I will teach the agents to do this. Git is our friend here, and having verified-good checkpoints is super valuable!
        I think I have a line on what happened and a solution for it. It turns out "modern" in the legacy codebase meant odb version ≥ v5, and Codex got very confused by the fact that I was calling the new 64-bit v7 format "modern".
          This caused it to make big mistakes refactoring some of the table and menu unpacking code which broke a lot of stuff.
          The solution I landed on is to rename all of my new "modern" stuff to "64bit" or just "64", and leave the older "modern" unpacker code untouched.
          Cleaning up this mess is taking a while, but I think I'll be on much better footing once it's done.
      Hi Scott!
        If you see this, then you've opened my Instant Outline!
      Dave: RE Frontier's menubar, and why I'm having to do extra work on this right now
        Frontier had two mechanisms for handling custom menus: user.menus (always present), and a callback that would update the menu bar based on the frontmost window.
          I haven't dug in too deeply on the full flow, so this is from memory.
        The issue I'm dealing with now has to do with tight coupling in C code between the legacy menu odb reader/unpacker, and the UI implementation.
          menuverbs.c has many references to QuickTime and Cancoon functionality. These have to be disentangled to load menubarType objects from the old odb, so that they can be migrated to the new v7 64-bit format.
          So it's not a single problematic function or area – it's a core design issue having to do with a lack of separation of concerns between menubarType in-memory and packed/saved data structures, and UI code.
          The solution I'm working on now is to coach Codex to create (more) stubs that compile in headless so that the UI-related symbols don't blow up the build. The stubs basically just return "success" so that the headless app keeps running without doing anything UI related.
            Most recent update from Codex this morning:
              Added headless shims/stubs to satisfy GUI-era/global symbols for headless builds using production menupack but NOT menuverbs: headless_mac_compat.c removed from test build to avoid duplicates; GUI shim now provides Finder proxy stubs, QuickDraw patterns, Cancoon stubs, config globals, and flconvertingolddatabase. However, save_migration_tests still fails at runtime with missing _config then _flconvertingolddatabase; we added the latter, but _config is still unresolved due to frontierconfig not being linked.
            And some minutes later, a glimmer of success:
              Menubar migration path: modern packer/unpacker is exercised during the migration run (see FRONTIER_MENU_TRACE output), and the migration completed without menu crashes. The modern writer is the only path used (legacy writer is bypassed), so menu payloads in test_save_migration-v7.root are emitted in BE64 form and load via the modern reader during that run. If you want an explicit proof point, I can add a small post-migration check that reopens test_save_migration-v7.root with the modern reader and validates a known menubar object length/fields.
          This, and dealing with over-use of globals are actually at the heart of the refactor!
      Dave: RE custom menu in Drummer
        I remember seeing this the first time I tried out Drummer back when you initially released it. I love that you carried the concept forward from Frontier!
        I'll admit to not having used it much. I do think it's possible to make headless frontier + Drummer do something similar to what Frontier did in its native UI WRT menus.
          Definitely not close to needing to figure out *how* though yet. ;-)
    December 9
      Dave: Here's the situation in a summary I said to Codex just now based on 4 or 5 hours of work trying to untangle menubarType from UI dependencies. This is basically a summary of the world as it existed when you and I both backed away from UserLand:
        Me to Codex: "We need to unwind this thread. We started with a seemingly very simple goal of getting the Frontier runtime to complete bootstrapping while allowing it to run the complete set of startup scripts. We landed on a major issue with menubarType migrations which sent us on a Snipe Hunt for why menubarType wasn't migrating correctly, which led to serious bugs in the migration pathway in headless, which in turn led to learning about stubs which were leading to 0-byte payloads for menus in the v7 roots, which in turn led us to where we are now, considering implementing a generalized GUI stub that will help us get past this type of issue the next time it comes up. And all because Frontier's C code never made a clear separation of concerns between UI and internal data formats (or for that matter in-memory data structures). Am I getting this right?"
          Codex: "Yes—that’s the story. Goal was “let startupScript finish.” We hit menubarType migration failures, traced to headless stubs duplicating menu blocks (yielding zero/garbage payloads), which forced us to investigate real packing/unpacking. That exposed tight coupling between UI-era code and data serialization. To break the loop we’re moving toward a shared headless GUI shim so we can run production menu code (and other GUI-tainted code) without the actual UI, instead of relying on brittle stubs. That separation-of-concerns gap in the original C code is the root cause of the detour. Next step is to finish wiring the shim and drop the menu fallbacks so migrations use the real path strictly."
          So yeah, that's where we're at. My (sincere) hope is that having dealt with tables, WPTexts, outlines, and scripts in similar ways, that menu objects are the final big hurdle to jump over. (Scalars and 64-bit migrations were a walk in the park compared to menubarType.)
      tl;dr: The top-priority and initial goal here is to ensure that all of the code and functionality of Frontier in 2005/2006 is able to run on modern machines and OSen. Once that milestone is reached the future opens up.
        And that's where the vision comes into play -- after I get to functional parity on the legacy bits, bringing them forward so that we can be sure we haven't lost anything that was important (and that our customers can follow along on the same path!)...
          Rule 1: No breakage (now with caveats about 64-bit math, AppleEvents, Win32 DLLs and file paths)
            Rule 1a': Make sure Dave's stuff works! ;->
    December 8
      This is my vision for headless Frontier! (written by Codex, guided by and reviewed by me without comment – so far)
        https://github.com/jsavin/Frontier/blob/develop/planning/_PHASE4_MULTI_USER_PLAN.md
      Starting to wire up verbs to kernel implementations
        We had explicitly taught the headless runtime to *not* run system.startup.startupScript because it caused a cascade of failures.
        The most obvious next step after getting some basics working was to stop disabling that, and systematically work through each failure, implementing glue as we go, for each verb that caused the tests to fail.
        We started with file.folderFromPath (and some friends), and then implemented date verbs.
        Next it failed to find user.scheduler because the headless runtime wasn't setting up system.paths correctly, which is how the user table lands in the global scope. Fixing that now...
          Amusingly, Codex tried initially to connect user.scheduler directly in C code with a hard-coded binding.
          I had to explain why this was wrong, and that the fundamental nature of the Frontier runtime is that code that lives in the database should be generally callable from UserTalk by its dotted address.
          We should never have to modify C code to add new UserTalk scripts or odb objects.
          I asked Codex to make a note about this philosophy in AGENTS.md so that it would remember this key design principle.
            Note to self: Remember to also teach Claude about AGENTS.md so they can "share" their memories.
        Still in low-level stuff here...
          frontier.getProgramPath () was returning the working directory for where we were when we ran the headless app.
            Now it returns the path to the executable which matches the designed behavior.
            But this is a decision point when it comes to system.startup.startupScript: Should Frontier headless base everything off of where the "system" root lives, or off of where the exe lives?
            I may need to sleep on this! It's a key decision point for how to move forward from here!
      Up Next
        Lots and lots of wiring up and testing of verbs. That's probably going to take the better part of a week.
        My hope is that now that I've crossed the big hurdles on odb format and migration, internal number representation, and fixing datetime issues, that a lot of the coming work will be much more straightforward.
        Progress continues... (To steal from the best: Still Diggin'!)
      64-bit migration status
        After many loops through re-running the Frontier.root migration from v6 (32-bit) to v7 (64-bit) after upgrading all number handling to use 64-bit internals, the build is finally clean and tests pass.
        All internal datetime processing now uses 64-bit unsigned integers representing the number of seconds since the Mac Epoch.
        Pushed a PR this afternoon with these updates along with the newly fixed verb registration bits (see below):
          https://github.com/jsavin/Frontier/pull/65
          Iterating on automated AI code review bugs called out by Codex and Claude bots.
        Fun fact: datetime now overflows ~584 billion years in the future instead of ~14 years in the future. ;-)
      Verb registration status
        For the first time, we have some verbs getting called from UserTalk code in headless, through to the kernel via the new automated verb registration system.
        Tests verified the following all work:
          clock.now () → automatically coerced to string for display: 12/8/2025; 2:17:21 PM
          3 + 4 → returns 7
          random (1, 100) → returns a random integer in the specified range
        All numbers are processed internally as 64-bit numbers, and dates are stored in 64-bit format eliminating the 2040 wrap-around
        And dialog.notify () displays text on the command line and waits for you to hit Enter.
        Oh, and file.getPathChar () returns "/" for headless on my modern POSIX Mac. ;-)
        I've collaborated with Codex on a plan for completely automating the "hydration" (binding) of kernel implementations with the fundamental design principles of the object database. We made a plan. It's still on a local branch though, so not yet visible on GitHub.
          The core idea is to do away with big switch statements and explicit registration of kernel verbs in runtime initialization.
          The proposal is to essentially treat the odb as canonical and load as much as possible from there, which is in keeping with the spirit of Frontier to keep everything about the runtime as dynamic as possible, and to avoid bootstrapping in C code anything that might change. The goal here is to make the whole system as dynamic as possible!!
    December 7
      Today I learned that lists and records in Frontier odbs are unpacked by the outline unpacker
        Apparently they are stored using outline-based data backing.
        My tests were failing trying to unpack a list object that contained a string4Type value.
        Currently debugging the issue in opunpackoutline and friends.
        Well this was a red herring. The code that was trying to pack tables was misidentifying types.
      Dave...
        I totally remember the pta (P'tahhhh) story. It resonates with me, but my go-to is either "Phew!" or "Yes!". 😉
        RE: Web app, yep – we're aligned on that. When I get to that point I will definitely look more closely at Drummer and Electron.
          ... and at your other tools/libs.
        RE: ATProto chat with ChatGPT, I can't join from my regular account
          I upgraded to "business" tier a few weeks back, and apparently group chat outside of my "team" isn't available. 😕
          I created a new free OpenAI account for this, and was able to join the chat.
        I've got a bunch of other unrelated stuff I have to do today so I may not get to much programming until late.
    December 6
      Working on 64-bit math and date compliance now
        Switched back to Codex now that Claude and I have written a ton of documentation today and yesterday.
        The key documents for this work are here:
          https://github.com/jsavin/Frontier/blob/develop/planning/phase3/numeric_type_system_modernization.md
          https://github.com/jsavin/Frontier/blob/develop/planning/phase3/date_time_format_standard.md
        tl;dr: Everything (or almost everything) is moving to 64-bit.
          Integer maths get a big upgrade
          Dates don't overflow in 2040 (even for things like timecreated and timemodified for non-scalars)
          Floating point math gets consistent across all modern platforms
            Weirdly, the Mac version was using 80-bit extended floating point values, but the Windows version was using 64-bit values, so floating-point math was inconsistent between the two platforms!
              PPC supported 80-bit extended floats, but in the Intel world only x87 supported it so older Windows boxes wouldn't be able to work with 80-bit floats
            We're switching to 64-bit IEEE floats everywhere because all modern systems support it without special compiler flags or external libraries
          system.compiler.language.constants.infinity is going to get really big!
      Verb Audit Update (DONE)
        Claude asked me for visibility into the script code in the system.verbs table, so I wrote a little script that exports scripts from a table into a file/folder hierarchy so it can see all the UserTalk code.
        It just completed the audit and I'm reviewing the output. Will push a PR with the audit details and UserTalk artifacts today.
        There are 60,731 lines of UserTalk code in Frontier.root, in 3,047 scripts (not including system.verbs.traps).
        PR is completed and merged to develop.
          https://github.com/jsavin/Frontier/pull/64
        Here's the output of this exercise:
          https://github.com/jsavin/Frontier/tree/develop/planning/phase3/processor_audits
          This will be super important when working with the AI agents to actually modernize the kernel verb implementations!
      An interesting tidbit about time in the UserTalk realm
        We have to move to 64-bit storage for things like timecreated and timemodified since the current implementation that uses signed 32-bit ints can't represent dates past about 2040.
        Consider the following UserTalk code:
          local (whenCreated = timecreated (@examples.letter))
          local (oneHourLater = whenCreated + (60*60) ) // Frontier times are in seconds
        If we have a WPText, for example, which was created near the 2040 boundary, then adding an hour to that time will result in a date in 1904!
        By implication, all integer math in the Frontier runtime needs to use 64-bit signed ints, not 32-bit. We can't treate datetime values in a special way because there's real code that does this kind of math (for example for time zone calculations).
        So I've added a TODO, which will happen sooner than later, to update all the integer math internals to be 64-bit, and to update the v7 64-bit root format to store integer scalars with 64-bit widths.
        Yet another layer of the onion peeled back!
        (While I'm at it, I'm going to make sure floats are also 64-bit.)
      Dave: Regarding porting the UI...
        I suspect that the fastest path using AI to help with Frontier UI is to start clean and build it as a web app, then wrap with Electron.
        Coding AIs know a fuck-ton about web apps because there's so much training data available.
        I could concievably make a native Mac app using Swift UI (and I've done some work in that environment before), but I think it might take longer, and also has the downside of being Mac only.
        A web app would have some key advantages:
          It would work on any OS
          It would be able to connect to remote headless Frontier instances
          It would (hopefully) be straightforward to integrate with Drummer or other tools/apps you've been building
          It might be easier to build a community around it since Swift UI is a much smaller dev community
    December 5
      TODO
        Look at the verbs in Drummer/DocServer, esp the ones for external apps -- wordpress, github, feedland.
      Hit a snag on the verb audit/porting work
        Claude was working on a fix to the byte-alignment of op object metadata (timemodified, timecreated, etc) in the new 64-bit v7 root format, and I noticed it was including font and style information which we'd explicitly removed in an earlier phase (when I was working with Codex).
        Claude didn't read the docs, and instead of updating the v7 packer to fix the issue, it updated the old one which I why I saw it thinking about font information.
        The issue we were trying to fix had to do with using 32-bit longs for date/times in the kernel, which would overflow after about 2040. This is similar to the infamous Y2K and UNIX Epoch issues. So we were working on changing it to use 64-bit integers instead. (This is now fixed!)
        So we changed gears to create a dispatcher that knows how to route to the correct implementation of oppack based on the version of the database. Now I've got one chunk of code that does the legacy unpacking, and two other chunks of code that do the modern packing/unpacking of op objects (and scripts).
        Before turning back to the verb audit, I need to make sure to review the other non-scalar object formats to ensure that we're getting what the AI promised -- a clean, fully 64-bit big-endian on disk v7 root format for all supported object types. (Should get that done today.)
      Verb Audit status
        I'm using Claude Code to audit all of the built-in verbs as parsed from kernelverbs.rc
        The output of this audit will be a very detailed plan for how to implement everything in headless
        Documents will be here: https://github.com/jsavin/Frontier/tree/develop/planning/phase3/processor_audits (working on a branch right now)
      Dave: Responding to the questions you raised today:
        What kinds of scripts will we be able to run?
          tl;dr: Anything that doesn't directly rely on GUI
          I'm auditing all of the kernel-level verb implementations now and making documentation for what they will do in headless
          There are some exceptions to what I said above about things that rely on GUI:
            target.set and target.get will still work. They're required for outline/script manipulation.
            op verbs will work (same reason)
            file and tcp I/O will get ported
            "Local" Guest Databases will work, meaning databases on the same system that's running the headless executable
            SCNS will work
            I will likely end up using stdio to implement some of the dialog verbs as command-line interactions
            Not sure what to do yet with the About Window and msg() calls
          Things that won't work until we have a GUI available
            Window manipulation (set/get position and size)
            Menus
            html dialogs (from the Windows world)
            Cards (from the classic Mac world) will probably never work
        What API should we implement so we can control it from Drummer and other potential UIs.
          Good question! I was thinking of a JSON or XML-RPC API to start -- JSON is probably easier from Drummer
          There might also be reasons to implement an API using stdio
          I haven't started thinking very deeply about this yet!
        How will we extend the verb set from outside?
          It would be awesome if the headless process could also work with user-local roots and scripts
          My initial thinking is that headless Frontier is a server process, and the GUI runs on the user's local machine, and that code running on the server on behalf of the user can also call local scripts, and access a local copy of user.root. But there are other ways to accomplish similar things.
            This is actually the direction I wanted to go in my last year or so at UserLand, but I didn't have the expertise or time to do it. AI has changed that equation!
    December 4
      Dave: I caught up on your notes from 12/4. Still processing a bit.
        I went to the Seattle Xcoders meetup tonight, and hoped to see Brent but he wasn't there.
        I'm working with Claude Code now on automating the verb bootstrapping in the headless runtime. Good progress so far, but not ready to show yet.
        I also cleaned up some crashing bugs earlier today and cleared out a bunch of legacy build stuff that's not relevant in the New World™.
        My goal is to land a very clean, scalable, and maintainable platform to build on moving forward that respects all of the stuff that the software world has learned in the last couple of decades, while not discarding all of the innovation we did at UserLand – much of which was lost in the siloed, corporate, VC-driven universe that had dominated the industry in the post dot-com era. (The AI era is changing the equation IMNSHO!)
    December 3
      TODO
        Read through Dave's IO here: https://drummer.land/dave.winer@gmail.com/dwSharedOutline.opml
      Frontier worknotes
        Codex got very stuck trying to figure out how to find objects in Frontier.root so I switched to Claude Code.
          Claude Code now has the concept of sub-agents which are defined in markdown (in English text) and have their own roles, permissions, and context window. The main agent can delegate to sub-agents for things like architecture planning, testing, etc. (Whatever you want.)
        Claude Code was able to relatively quickly get past the final hurdles to open Frontier.root and run a script using the headless build.
          The tracer-bullet I used initially was to call clock.now() and get back a date/time string.
        Up next
          Start working through the kernel verb implementations to light up real functionality in headless.
            This will likely take the form of a combination of porting existing implementations and creating new POSIX-compliant ones where needed.
            The goal is to keep everything clean, thread-safe, and tested as we go.
          Strategy for this phase of the work is written out here: https://github.com/jsavin/Frontier/tree/develop/planning/phase3/kernel_verb_porting
  November 2025
    November 18
      Hello World!