Catalog · How the catalog works
lazycodingagent
Lazy Coding Agent, Lazarus free pascal AI assistant
Anyone may press Interesting, signed in or not. It helps others find this project.
README
LazyCodingAgent
[https://lazycodingagent.com/](https://lazycodingagent.com/)
LazyCodingAgent is a cross-platform desktop AI coding assistant and editor built with Free Pascal and Lazarus (LCL). Inspired by tools such as Hermes, Cursor, and Codex, it provides a focused, high-productivity development workspace.
The interaction model is a native Lazarus/LCL desktop app (menu bar, docked panels, modal Settings and task dialogs), while agent capabilities are inspired by tools such as Hermes, Cursor, and Codex.
Status: Multi-window workspace layout implemented. AI/model execution is in active integration.
Community
- Contributing — workflow, CI, Lazarus UI conventions, and tests
- Code of conduct
- Security policy — report vulnerabilities via GitHub private advisories
- License — MIT
Key Features & Workspace Layout
1. Lazarus Visual Form Designer Architecture
- Designed directly with Lazarus Visual Designer (
mainunit.lfmandmainunit.pas). - LCA Design palette (
packages/LcaDesignSystem/): themed tab bars, buttons, combos, markdown view, terminal panel, and surfaces stream on.lfmforms after runningscripts/install-lca-lazarus(or.baton Windows). - Published event handlers hooked cleanly into the state management and theme engine (
LcaTheme,uThemeHooks.pas).
2. Modern Dark-First Design & Painted Chrome
- Crisp, modern theme with prominent boundary lines (
BorderStrongandBordertokens) and high-contrast styling. - Painted main-window chrome (all platforms): nav rail (
TLcaPaintNavRailButton), action/chrome buttons (TLcaPaintButton), composer combos (TLcaPaintComboBox), nav lists (TLcaPaintNavList), and tab strips (TLcaThemedPageTabBar) use LCA custom paint — no native Qt/GTK button or combo styling on those controls. - Stable cross-platform combo layout: combo Height and ItemHeight come from the form resource (
.lfm); painted combos do not resize at theme apply time. LegacyTLcaThemedComboBoxin dialogs still usesStyleComboBoxinLcaTheme.pas. - Designer-first layout: the main window streams LCA Design and stock LCL controls in
.lfmfiles (TLcaPaint*,TLcaMarkdownView,TLcaTerminalPanel,TSynEdit, etc.). Openmainunit.pasin Lazarus (F12) to edit the full layout. - Native islands (intentionally stock LCL): code editor (
TSynEdit), chat prompt (TMemo), project tree (TTreeView), embedded terminal (TLcaTerminalPanelPTY view), and some Settings/dialog controls. - Clean Minimalist Top: Full vertical viewport space for navigation, chat, and guidelines panels, with comprehensive menu bar and status bar controls.
- Seamless Dark Mode default with instant Light Mode toggle via
View > Toggle Light / Dark Theme. - Navigation rail: icon captions, tooltips, and accent
Activestate on painted rail buttons. - Accent text selection on navigation lists (painted rows — accent text, no OS highlight band).
- LCA-painted scrollbars on chat/plan markdown (
TLcaMarkdownView) and nav file/log/error lists. Scrollbars on the editor, prompt memo, tree, and terminal still follow the OS widget theme. - Linux: Qt5 widgetset is recommended (
./scripts/install-lca-lazarus.sh --widgetset=qt5,lazbuild --widgetset=qt5) for consistent LCL behavior with painted controls. - Linux main menubar: in-app dark/light toggle syncs the native top menu bar (File, View, …) via the LCL widgetset — Qt5
QMenuBarstylesheet, or GTK2/GTK3 colors/CSS — so labels stay readable; dropdown menus are left on the OS theme. macOS uses the native menu bar (no in-app menubar sync). - Clean splitters allowing custom width resizing between all panels.
Platform verification checklist
| Check | Windows | Linux (Qt5 recommended) | macOS (Cocoa) |
|---|---|---|---|
| Nav rail icons + accent selection | Yes | Yes | Yes |
| List rows: accent text, painted scroll | Yes | Yes | Yes |
| Editor + terminal monospace (no wide char gaps) | Consolas / Cascadia | DejaVu / Liberation | Menlo / SF Mono |
Primary / Cancel / Stop (main form TLcaPaintButton) |
Painted | Painted | Painted |
| Markdown + nav list scrollbars | LCA painted | LCA painted | LCA painted |
| Editor / prompt / tree scrollbars | OS theme | OS theme | OS theme |
| Light/dark toggle coherent | Yes | Yes | Yes |
| Main menubar readable in app dark mode | Yes | Yes (Qt5/GTK) | OS menu |
3. Docked panels (show / hide)
- Navigation, guidelines, utility, and terminal panels dock on the main form.
- Window → Panels and panel ✕ buttons toggle visibility; sizes and visibility persist in workspace settings.
4. Vertical Navigation Rail & Panel
- Sleek 56px left navigation rail with icon-only slots, tooltips, and accent active indicator for:
- ⌂ Home: Workspace dashboard and overview.
- ◫ Projects: Project explorer and file tree.
- 💬 Sessions: Per-workspace chat sessions (active and archived lists, archive/restore/delete actions).
- ⚡ Bots: Custom coding agents and prompt setups.
- Connected content area with contextual actions for the active navigation selection.
5. Primary AI Agent & Chat Workspace
- Multiple parallel sessions per workspace: each session has its own
TAgentEngineand async run thread. Switch sessions from the left Sessions nav without stopping other sessions. Background runs continue when you switch workspace and return later. - New chat: Sessions → + New Chat Session; the center Chat tab shows the active session name.
- Single chat surface (no session tab strip). Archive, restore, or delete sessions from the Sessions list.
- Archive via Sessions panel (Archive Session / Restore Session),
Deleteon an active session, orShift+Deleteto permanently delete an archived session. - Clean hero greeting:
What should we build in <project name>?. - Embedded workspace badge and live conversation history stream.
- Multiline prompt composer with mode dropdown selector:
- Ask: Fast Q&A without direct workspace mutations.
- Plan: Architecture design, checklists, and specs.
- Agent (Default): Full autopilot coding and editing.
- Instant mode and model switching synced with application state and status bar.
- Model selector dropdown supporting
anthropic/claude-3.7-sonnet,Hermes-4-70B,Hermes-4-405B(Nous Research),openai/gpt-4o,deepseek/deepseek-r1, etc. (OpenRouter slugs where noted).
6. In-app User Guide
- Help → User Guide… (F1) opens a searchable help browser with topics under
help/, including how the agent and tools work. - After
lazbuild, runscripts/post-build.sh(orscripts/post-build.cmdon Windows) to copyhelp/andassets/next to the executable; when developing from the IDE, topics also resolve from the projecthelp/folder.
7. Debugging mode and project rules
- Debugging Mode (Settings → Agent Behavior): when enabled, full tool JSON results appear in the chat history; when disabled, only tool errors are shown (successful tool calls stay hidden in chat).
- Project Rules (main menu → Workspace → Project Rules…): edit per-workspace Markdown files under
<workspace>/.rules/*.md. Combined rule text is injected into the agent system prompt for Ask, Plan, and Agent modes.
8. Reserved Context & Instructions Panel
- Dedicated right-side panel for workspace guidelines, coding rules, and instructions context.
9. Utility panel (right)
- Utility panel with a
TPageControl: Execution Detail and Plan. - Hidden by default; toggle via Window → Panels → Utility Panel.
10. Integrated terminal (bottom panel)
- View → Terminal toggles a full-width bottom dock (above the status bar) with a real PTY shell (
$SHELL//bin/bashon Unix,%COMSPEC%on Windows). - Terminal chrome is on the main form via
TLcaTerminalPanel(LcaTerminalPanel.pas);uTerminalPanel.pasis a thin alias type for app code. - Docked height defaults to about one quarter of the client area (resizable splitter); floating window size is stored separately from docked height.
- When you open the panel with an active workspace, the shell starts in the workspace root (
pwd/cd); switching workspaces restarts the shell in the new folder if the terminal is already visible. - Powered by a vendored copy of TerminalEmulator in
third_party/TerminalEmulator(BSD 3-Clause; seethird_party/TerminalEmulator/LICENSE). Windows requires Windows 10 1809+ (ConPTY). - Linux PTY: the embedded terminal needs
forkptyfrom libutil (Debian/Ubuntu:bsdutils/util-linux). Build the terminal packages via./scripts/build-terminal-deps.shbefore compiling the app. If the panel stays blank, check the status bar for a PTY error and verify$SHELLor/bin/bashexists.
Terminal manual test checklist
| Step | Linux / macOS | Windows |
|---|---|---|
| View → Terminal shows bottom panel | pwd matches workspace |
cd matches workspace |
| Resize splitter; restart app | Height restored | Height restored |
| Hide / show terminal & utility | Yes | Yes |
| Theme toggle | Colors readable | Colors readable |
| Interactive TUI | ls colors; optional vim/nano |
dir, git status |
Technology Stack
- Free Pascal (FPC)
- Lazarus IDE
- Lazarus Component Library (LCL)
- Chat history, Markdown file preview, and Help topics use
TLcaMarkdownView— a canvas-painted Markdown subset (no HTML engine). - Embedded SQLite: vendored amalgamation in
third_party/sqlite/, static link viaLazySqliteStatic— no systemlibsqlite3at runtime. App settings and workspace registry useglobal.db; chat and syntax schemes still use JSON until later M1 work. Seefuture-plan/Lazarus_Embedded_Storage_and_Vector_Plan.mdandfuture-plan/sqlite/README.md.
Building & Running
Clone the repository normally; third_party/TerminalEmulator is included in the tree (required for the integrated terminal and TerminalFramework / ViewLCL packages).
Install terminal packages, LcaDesignSystem runtime, and (for the Form Designer) the LCA Design palette once per machine:
Linux / macOS:
chmod +x scripts/install-lca-lazarus.sh
./scripts/install-lca-lazarus.shWindows (use .cmd if PowerShell blocks .ps1 scripts):
scripts\install-lca-lazarus.bat(Same as install-lca-lazarus.cmd.) Or: powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\install-lca-lazarus.ps1
Close Lazarus before running the full install: the script installs LcaDesignSystemDesign (palette only) and runs lazbuild --build-ide. The runtime LcaDesignSystem package is linked for builds but not embedded in lazarus.exe.
On Linux, plain lazbuild defaults to GTK2, so a full install without a widgetset rebuilds the IDE for GTK2. To rebuild the Lazarus IDE itself for Qt5 (apt install under /usr/share/lazarus), close Lazarus and run:
chmod +x scripts/rebuild-lazarus-ide-qt5.sh
./scripts/rebuild-lazarus-ide-qt5.shThat script creates a writable units/<cpu>-linux/qt5 directory (see fpc -iTP; or run ensure-lazarus-qt5-units-dir.sh) with sudo when needed, then runs lazbuild --widgetset=qt5 --build-ide so your IDE (SynEdit, LCA Design, etc. from ~/.lazarus) is linked into ~/.lazarus/bin/lazarus. Do not copy /usr/share/lazarus/4.8.0/lazarus over that file — the system binary is a smaller stock build without your installed design packages. startlazarus and the desktop entry use ~/.lazarus/bin/lazarus; /usr/share/.../lazarus is only the apt source tree.
For LCA Design packages on Qt5, pass the same widgetset to the install script:
./scripts/install-lca-lazarus.sh --widgetset=qt5
# or: LCL_WIDGETSET=qt5 ./scripts/install-lca-lazarus.shIf Lazarus hangs on startup after an install, run scripts\recover-lazarus-ide.bat, then reinstall with install-lca-lazarus.bat (Lazarus closed). See packages/LcaDesignSystem/README.md.
Use --link-only for CI/headless builds without IDE palette install or IDE rebuild (then pass --widgetset=qt5 to lazbuild when building the app, if desired).
Static SQLite (LazySqliteStatic)
Before the first lazbuild (or after a clean clone), compile the embedded SQLite object and register the package:
Linux / macOS:
chmod +x scripts/install-lazarus-sqlite.sh
./scripts/install-lazarus-sqlite.shWindows: compile the amalgamation with MinGW-w64 (WinLibs or MSYS2 on PATH; CI installs WinLibs via winget). Run scripts\install-lazarus-sqlite.bat. Linking uses FPC’s internal linker, uSqliteWinEmbedBridge (Win32 forwarders), and MinGW import libs from ci-lazbuild.ps1. Optional SQLITE_CC=msvc or clang for experimental MSVC objects; LCA_SQLITE_USE_WINSQLITE3 falls back to OS winsqlite3.dll. See docs/sqlite-windows-static-review.md.
scripts\install-lazarus-sqlite.batIf your policy blocks .ps1 files, use the .bat wrapper (same as install-lca-lazarus.bat). Equivalent: powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\install-lazarus-sqlite.ps1
This runs scripts/build-sqlite-static.sh (or .ps1) and links packages/LazySqliteStatic/LazySqliteStatic.lpk for lazbuild. You do not need to edit Project → Options → Linker manually: lazycodingagent.lpi already sets Libraries to packages/LazySqliteStatic/src and depends on LazySqliteStatic.
Lazarus IDE: open lazycodingagent.lpi and Build after the install script above (same as CLI). Compile LazySqliteStatic.lpk once in the IDE if the package is not resolved. The main app links SQLite through uSqlite3Embed; it does not open databases at startup yet.
Verify: lazbuild tests/test_app_database.lpi then ./tests/test_app_database (or run tests/run_tests.sh, which includes this when lazbuild is available).
Legacy scripts scripts/build-terminal-deps.sh / .ps1 only link terminal packages; prefer install-lca-lazarus.*.
If lazbuild is not on PATH, set $env:LAZBUILD to your lazbuild.exe (for example C:\lazarus\lazbuild.exe).
Form designer: Chrome controls (TLcaThemedPageTabBar, TLcaMarkdownView, TLcaTerminalPanel, etc.) stream on mainunit.lfm from the LCA Design palette after running the install script. mainunit.lfm is the source of truth for dock layout (Align-based panels and spacer hosts); edit it in the Lazarus IDE. Use scripts/gen-main-lfm.py only as a legacy nav-rail scaffold—do not overwrite the live .lfm without updating that script first. Open forms from the .pas unit (View → Toggle Form Unit / F12).
Open lazycodingagent.lpi in Lazarus, or build from the command line:
Linux / macOS:
./scripts/install-lca-lazarus.sh --link-only
./scripts/install-lazarus-sqlite.sh
lazbuild lazycodingagent.lpi
./scripts/post-build.shOn Linux, prefer the Qt5 LCL widgetset (lazbuild --widgetset=qt5 lazycodingagent.lpi or use make build, which passes --widgetset=qt5). The project file pins Widget set: qt5 so IDE Build matches command-line builds. make build does not refresh the Form Designer (no LcaDesignSystemDesign install or --build-ide); after LCA package changes, close Lazarus and run make ide or ./scripts/install-lca-lazarus.sh --widgetset=qt5. GTK2/GTK3 are also supported with GTK menubar sync.
Running on Linux: make runs post-build.sh automatically. Start the app with ./scripts/run-linux.sh (on Wayland: sets QT_QPA_PLATFORM=xcb for Qt5 builds or GDK_BACKEND=x11 for GTK2). You can also run ./lazycodingagent directly; Qt5 builds set QT_QPA_PLATFORM=xcb in uLinuxDisplayEnv.pas before the LCL loads Qt (same effect as IDE Run env). GTK2 builds set GDK_BACKEND=x11 the same way when WAYLAND_DISPLAY is set.
Local web search (SearXNG)
The agent web_search tool can use a local SearXNG instance (no Brave/Tavily API key). This repo ships a dev-only Compose stack under docker/searxng/ with JSON search enabled for LazyCodingAgent. Full notes: docker/searxng/README.md.
Requirements: Docker with Compose.
cd docker/searxng
cp .env.example .env
docker compose up -dCheck JSON search: curl -s 'http://127.0.0.1:8080/search?q=test&format=json' | head -c 200 (should print JSON, not HTML). Stop with docker compose down from that directory.
In LazyCodingAgent:
- Settings → Tools → Web Search — enable Web Search, Add provider SearXNG, instance URL
http://127.0.0.1:8080, then Test and OK. - Allow local hosts (blocked by default): set
AllowPrivateInstances=trueunder[WebSearch]in your userconfig.ini, or launch withLCA_WEB_SEARCH_TRUSTED_LOCAL=1(for exampleLCA_WEB_SEARCH_TRUSTED_LOCAL=1 ./scripts/run-linux.sh).
Brave and Tavily are configured in the same settings screen with API keys. See Help → Web Search in the app for provider behavior and limits.
Raspberry Pi 4/5 (64-bit Linux / aarch64)
LazyCodingAgent is not tuned for low-RAM boards, but the same Linux aarch64 build applies on Raspberry Pi OS (64-bit) and similar distros. You need Lazarus 3.0+; if apt’s Lazarus is too old, use fpcupdeluxe for a current FPC/Lazarus install.
Packages (Debian / Raspberry Pi OS bookworm+): git, fpc, lazarus, lcl, libqt5pas-dev, qtbase5-dev, libssl-dev, build-essential, and the same SynEdit prep as desktop Linux (ci-prepare-lazarus-deps). For the integrated terminal, ensure util-linux / bsdutils (forkpty).
Build on the Pi (native, Qt5 recommended):
git clone <your-fork-or-upstream> lazycodingagent && cd lazycodingagent
chmod +x scripts/*.sh
./scripts/ensure-lazarus-qt5-units-dir.sh # once, if apt Lazarus needs a writable qt5 unit dir
./scripts/install-lca-lazarus.sh --link-only --widgetset=qt5
./scripts/install-lazarus-sqlite.sh
lazbuild --widgetset=qt5 lazycodingagent.lpi
./scripts/post-build.sh
./scripts/run-linux.shThe binary is under lib/aarch64-linux/lazycodingagent. Use Qt5 + XWayland (run-linux.sh sets QT_QPA_PLATFORM=xcb on Wayland) for the same windowing behavior as desktop Linux. Expect long lazbuild times on Pi hardware; 4 GB RAM may need swap during linking.
Releases: tagged builds publish an arm64 .deb for Pi / ARM64 Linux (system Qt5 and libssl3 via Depends). The portable AppImage remains x86_64 only.
arm64 .deb on Pi: sudo apt install ./LazyCodingAgent-*-arm64.deb pulls in Qt5 and OpenSSL 3 runtime packages. HTTPS (Settings Fetch Models, chat) needs libssl3 (libssl.so.3); the package declares that dependency. If you built from source instead of the .deb, install libssl3 yourself: sudo apt install libssl3.
Release QA on Pi (64-bit OS): After installing a new arm64 .deb, confirm startup and the editor load cleanly (catches SynEdit / form-resource mismatches that only appear at runtime on distro Lazarus builds):
sudo apt install ./LazyCodingAgent-<version>-arm64.deb- Launch from the menu or
/usr/bin/lazycodingagent— there must be no dialog about unknown SynEdit properties (for exampleMaxExtraMarksColums). - Open the Editor tab; line numbers and gutter should render.
- Optional: Settings → Fetch Models (HTTPS /
libssl3on the device).
Older release .deb packages built before the SynEdit gutter .lfm trim may fail at step 2; upgrade to a release that includes that fix or build from current main.
Linux troubleshooting:
- No window on Wayland (GTK2 build): The process runs but nothing appears (not even the splash). Default
lazbuildon Linux uses GTK2, which often fails to map windows on Wayland. UseGDK_BACKEND=x11 ./lazycodingagent,./scripts/run-linux.sh, rebuild with the Qt5 widgetset, or use an X11 session. Requires XWayland (echo $DISPLAYshould be set, e.g.:0). If a window still does not appear on X11, check multi-monitor or saved off-screen bounds in workspace state under your config directory. - Title bar drag / resize works in IDE Run but not when launching the built exe (Qt5 + Wayland): IDE Run injects
QT_QPA_PLATFORM=xcb; rebuild after pulling fixes so startup sets the same, or use./scripts/run-linux.sh/QT_QPA_PLATFORM=xcb ./lazycodingagent. - Canberra Gtk-Message:
Failed to load module "canberra-gtk-module"is an optional event-sound module; the GUI still runs. Install withsudo apt install libcanberra-gtk-module(Debian/Ubuntu, GTK2 builds), orGTK_MODULES= ./lazycodingagent. install-lca-lazarus.sh/mkdir: Permission deniedon--build-ide: With apt Lazarus (/usr/share/lazarus), rebuilding the IDE for a new widgetset (e.g. qt5) tries to createunits/<cpu>-linux/qt5under the system tree (seefpc -iTP), which is root-owned. Use--link-only --widgetset=qt5for command-line builds, or run./scripts/ensure-lazarus-qt5-units-dir.shonce (sudo), then rerun the full install (Lazarus closed). A user-writable Lazarus install (fpcupdeluxe) avoids this entirely.- Lazarus exits when opening
lazycodingagent.lpi: Access violation inTryLoadOwlIconIntowhile the designer loadsmainunit. Rebuild LCA for qt5, thenlazbuild --widgetset=qt5 --build-ide(close Lazarus first;--link-onlydoes not update the IDE). Or run./scripts/install-lca-lazarus.sh --widgetset=qt5. On Wayland/Qt5, use./scripts/run-lazarus-linux.shif the IDE dies with a Wayland protocol error. Match Project → Compiler Options → Widget set: qt5. Emergency:./scripts/recover-lazarus-ide.sh.
Windows:
scripts\install-lca-lazarus.cmd --link-only
scripts\install-lazarus-sqlite.ps1
lazbuild lazycodingagent.lpi
scripts\post-build.cmdCI: GitHub Actions workflow .github/workflows/build.yml runs the same flow on Linux (x86_64 and aarch64 / ubuntu-24.04-arm with Qt5), Windows, and macOS (headless --link-only install, no IDE palette rebuild), including install-lazarus-sqlite and the test_app_database console test on Linux jobs. Linux uses distro Lazarus; Windows and macOS install pinned Lazarus 4.8 from SourceForge on macos-14 (Apple Silicon / aarch64) and macos-15-intel (Intel / x86_64; GitHub plans to retire Intel macOS runners around 2027). The Homebrew Lazarus cask is disabled for CI. ci-prepare-lazarus-deps links SynEdit from the Lazarus tree. On Windows, gen-owl-branding.bat builds lazycodingagent_appicon.res with the Windows SDK rc.exe when available (compile-lazycodingagent-appicon-res.ps1); FPC windres is only a fallback for Lazarus-only machines.
Releasing
Pushing a version tag builds Windows, Linux, and macOS packages and publishes a GitHub Release.
- Choose the release version (for example
0.1.0). - Tag and push:
git tag v0.1.0thengit push origin v0.1.0. - Open Actions → Release on GitHub and wait for
build-windows,build-linux,build-linux-aarch64,build-macos-aarch64,build-macos-x86_64, andpublishto finish. - Download assets from the release page for that tag:
LazyCodingAgent-0.1.0-win64-Setup.exe— Windows installer (Inno Setup)LazyCodingAgent-0.1.0-amd64.deb— Debian/Ubuntu/Mint on x86_64 (system Qt5 runtime viaDepends)LazyCodingAgent-0.1.0-arm64.deb— Debian/Ubuntu/Raspberry Pi OS 64-bit (ARM64; system Qt5 viaDepends)LazyCodingAgent-0.1.0-x86_64.AppImage— portable Linux build on x86_64 (Qt5 bundled via linuxdeploy)LazyCodingAgent-0.1.0-aarch64.dmg— macOS Apple Silicon (Cocoa app bundle; drag Lazy Coding Agent to Applications)LazyCodingAgent-0.1.0-x86_64.dmg— macOS Intel (same install flow; pick the DMG that matches your Mac)
The workflow .github/workflows/release.yml runs parallel jobs like .github/workflows/build.yml (including install-lazarus-sqlite via release build scripts on Linux/macOS and a dedicated step on Windows): Windows mirrors build.yml and runs scripts/build-windows-installer.ps1 against installer/lazycodingagent.iss. Linux amd64 uses ubuntu-24.04 (apt Lazarus 3.0+; 22.04’s Lazarus 2.2 is too old), builds with --widgetset=qt5 (scripts/ci-linux-qt5-release-build.sh), then scripts/build-linux-deb.sh and scripts/build-linux-appimage.sh. Linux arm64 uses ubuntu-24.04-arm, the same Qt5 release build, and an arm64 .deb only (no AppImage). macOS builds twice: Apple Silicon on macos-14 and Intel on macos-15-intel, each with SourceForge Lazarus 4.8, --widgetset=cocoa (scripts/ci-macos-release-build.sh), then scripts/build-macos-dmg.sh (hdiutil DMG with Lazy Coding Agent.app). Release DMGs are ad-hoc signed; macOS may block the first launch until you right-click the app and choose Open, or run xattr -cr on the app (Developer ID notarization can be added later). A final publish job uploads all artifacts. Tags must match v* (for example v1.2.3); the v prefix is stripped for file names and the release title.
Linux QA (manual): CI smoke-tests the built binary, packaged .deb (scripts/smoke-linux-deb.sh), and AppImage under Xvfb with QT_QPA_PLATFORM=xcb. Before shipping a tag, test the AppImage and .deb on real desktops under X11 and Wayland — detachable panels, docking, and multi-monitor behavior differ between compositors. The app sets QT_QPA_PLATFORM=xcb on Wayland when unset (uLinuxDisplayEnv.pas); verify that still works for your environment.
Local Linux packages (optional): after a Qt5 lazbuild and post-build.sh:
export APP_VERSION=0.0.0-local
./scripts/build-linux-deb.sh
./scripts/build-linux-appimage.shDEB installs to /usr/lib/lazycodingagent with a /usr/bin/lazycodingagent wrapper; runtime libraries come from distribution packages (dpkg-shlibdeps, plus an explicit libssl3 dependency for HTTPS). The AppImage bundles Qt5 from the build host — match the ubuntu-24.04 CI environment when producing release-quality AppImages locally.
Local installer (optional): after lazbuild and post-build.ps1, install Inno Setup 6 and run:
./scripts/build-windows-installer.ps1 -Version 0.0.0-localOutput is written to dist/.
Local macOS DMG (optional): after a Cocoa lazbuild and post-build.sh into the app bundle Contents/MacOS folder:
export APP_VERSION=0.0.0-local
./scripts/build-macos-icon.sh # optional if installer/macos/lazycodingagent.icns exists
./scripts/build-macos-dmg.shManual IDE install: compile LcaDesignSystem.lpk (runtime), then LcaDesignSystemDesign.lpk → Use → Install (after terminal packages). Do not install the runtime package into the IDE.
If the Lazarus IDE hangs when opening this project, use recover-lazarus-ide, or quit Lazarus and remove lazycodingagent.lps (session file), then open lazycodingagent.lpi again.
HTTPS for LLM providers (Fetch Models, chat, agent)
All HTTPS traffic goes through uLlmClient.pas (Settings Fetch Models, agent completions).
| Platform | Transport | Notes |
|---|---|---|
| Windows | WinHTTP + Schannel (uWindowsHTTP.pas) |
HTTPS does not need OpenSSL DLLs. Connect/send timeouts and response read timeout follow Settings → Agent Behavior (defaults 60s connect, 600s read). Retries and backoff match Linux/macOS. |
| Linux / macOS | fphttpclient + opensslsockets |
OpenSSL 3 runtime (libssl3 on Debian / Raspberry Pi OS bookworm+). The project vendors a small FPC openssl unit tweak so libssl.so.3 is found (see third_party/fpc-openssl3/). ConnectTimeout and IOTimeout use the same Settings values (defaults 60s / 600s). Failed requests retry with exponential backoff (Settings → Agent Behavior; default 3 retries from 1s). |
If Fetch Models or chat fails with an OpenSSL error on Linux, install the runtime package: sudo apt install libssl3 (on some releases the package name is libssl3t64). You do not need libssl-dev to run the app. The app surfaces a dialog instead of crashing when SSL is unavailable. On macOS, use system libs or Homebrew openssl@3 as usual.
Architecture & Unit Structure
lazycodingagent.lpr— Application entry pointmainunit.pas/mainunit.lfm— Main form: nav rail, nav body, centerTPageControl, utilityTPageControl, terminal view, menus, splitters, status barpackages/LcaDesignSystem/— LcaDesignSystem runtime package (LcaTheme, LCA palette components, Win32 paint helpers)uTerminalPanel.pas— Alias forTLcaTerminalPanel(PTY +TTerminalLCLViewinside the design-system component)uMainFileEditor.pas— SingleTSynEditload/save/highlighteruPlanView.pas— Plan utility tab (path, build, memo)third_party/TerminalEmulator/— Vendored TerminalEmulator: TerminalFramework + ViewLCL packages (seeVENDORED.mdthere)uNavigationPanel.pas—TNavContentControlbinds to streamed nav controls on the main formuChatPanel.pas— Binds composer memos/combos/buttons; chat history onTLcaMarkdownViewpackages/LcaDesignSystem/src/LcaMarkdownView.pas— Canvas Markdown preview for chat, center preview, and HelpuPanelDetach.pas— Detach navigation, chat, guidelines, utility, and terminal panels to floating windowsuThemeHooks.pas— App hooks (SynEdit gutter); registersLcaThemeHooksfor LCA components and terminal viewuChatSessionStore.pas— Per-workspace JSON persistence for chat sessions (messages, archive flag)uChatSessionHub.pas— Per-workspace session hub: oneTAgentEngineper session, parallel runs, save/shutdownuWorkspaceState.pas— State management; bounds, docking, modes, themes, and LLM settings inglobal.dbpackages/LcaDesignSystem/src/LcaTheme.pas— Dark/light design tokens, platform chrome (ApplyPlatformChrome), ComboBox/list owner-draw; on Windows,LcaThemeWin32Buttons.pascustom-paints primary/cancel/destructive buttonsuAppTypes.pas— Shared enumerations, modes, and helpersuAgentTypes.pas— Chat roles, LLM providers, tool schemas, and token usage recordsuAgentEngine.pas— Autonomous ReAct execution loop, state management, and LLM communicationuAgentRules.pas— Per-workspace.rules/*.mdload/save for project rulesfrmWorkspaceRules.pas/frmEditRule.pas— Project rules editor (main menu)uAgentToolBase.pas— Base tool abstract class (TAgentTool), session context, JSON helpers (ToolError,ToolResultFromJson), mode gatinguAgentToolPaths.pas— Workspace path sandbox, byte I/O, glob matching, symlink/reparse handlinguToolProcessCore.pas— Shared subprocess runner (stdout/stderr caps, timeouts, changed-path tracking)uAgentTools.pas— Tool factory and registry (TAgentToolRegistry) aggregating modular tool classesuToolReadFile.pas—read_file(16 MiB cap, UTF-8/binary checks)uToolWriteFile.pas—write_fileuToolApplyPatch.pas/uToolEditFile.pas—apply_patchunified diff andedit_filesearch-replaceuToolListDirectory.pas/uToolGlob.pas— directory listing and glob (500 entry cap)uToolSearchCode.pas—search_code/ aliasgrep(regex, 500 match cap)uToolRunProcess.pas—shell(aliasesterminal,run_process); Windows usescmd.exe /C, Unix uses/bin/sh -cuToolDiagnostics.pas— cached diagnostics + Agent-mode builds (auto-detected toolchains or explicitcommand)uBuildTargetResolver.pas— maps workspace targets/manifests to build invocationsuToolGit.pas— read-only git inspect (status/diff/log/show)uToolCreatePlanFile.pas— Plan-mode.plan/plan-*.mdwriteruToolTodo.pas— session task list (aliasplan)uMainWorkspace.pas— Compatibility alias unit
Agent tools (JSON contract)
Advertised tools: read_file, write_file, list_directory, glob, search_code, apply_patch, edit_file, shell, diagnostics, git, todo, create_plan_file.
Tool messages returned to the LLM are JSON strings. Failures include an error field; patch failures often add error_kind (context_mismatch, format, hunk_count_mismatch, incomplete_hunk, invalid_hunk, empty_patch, patch_apply), plus optional path, line, hint, and partial when a multi-file patch stops mid-batch. Successful apply_patch may include warnings when minor hunk headers were auto-corrected.
| Mode | Write / shell / patch | Plan files |
|---|---|---|
| Ask | Blocked | Blocked |
| Plan | Blocked | create_plan_file allowed |
| Agent | Full mutating set | Allowed |
Running tool integration tests
tests/run_tests.sh / .bat compile tool-driver tests and, when lazbuild is on PATH, run tests/test_app_database (embedded SQLite M0: global.db / workspace.db round-trip via IAppSettingsRepository).
Manual check: parallel chat sessions
- In workspace A, start an agent run in session 1; switch to session 2 (nav or tab) and start another run — both should finish; session 1 transcript updates when re-selected.
- Switch to workspace B while A still has a run; return to A — run completed or still active; messages persisted.
- Archive an active session — run stops; session appears under Archived; composer disabled until restored.
- Close the app with multiple runs — confirm prompt to stop all runs; exit cleanly.
- Toggle dark/light theme and resize the chat dock — no
ChangeBoundsloop.
Requires FPC, Lazarus lazutils on the unit path, and Python 3:
tests\run_tests.battests/run_tests.shBuilds tests/tool_driver.lpr and runs tests/test_local_tools.py (patch, path sandbox, shell, diagnostics fixtures ported from lazcodingagent).

