Blog › ICP guides

LiveCode developer on retainer: open file lost update, RunRev LiveCode developer, LiveCode Community Edition developer on monthly retainer

October 9, 2026 · ~15 min read

A LiveCode developer was maintaining a multi-user inventory management application for a wholesale auto parts distributor. The application was a LiveCode 9.6.9 desktop stack that ran on 5 Windows 10 workstations simultaneously. Because the application had been migrated from an original HyperCard stack in 2003, the inventory data was still stored as a pipe-delimited plain-text file (\\server\inventory\stock_levels.txt) on a Windows Server 2019 SMB share. The LiveCode handler updateStockLevel read the entire file with open file tFilePath for update; read from file tFilePath until end of file; close file tFilePath, parsed all 1,200 lines into a LiveCode array, updated the matching SKU quantity in memory, then wrote the entire file back with open file tFilePath for write; write tAllLines to file tFilePath; close file tFilePath. During a busy morning receiving shift when 5 operators processed orders simultaneously, 3–5 inventory count discrepancies appeared in the weekly stock audit: the warehouse scanner showed 147 units of SKU-4821 received, but the system showed 148. Silent inventory count discrepancies per week: 3–5 → 0 after switching from monolithic read-modify-write to a per-station delta append log consolidated nightly.

The root cause was a lost-update race condition. LiveCode’s open file tFilePath for write maps to the Windows fopen(path, "wb") call, which opens the file with CreateFile(... OPEN_ALWAYS ...) using the default dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE. This means the open file for write call does not prevent another workstation from simultaneously opening the same file for writing — no exclusive lock is acquired or held during the read-modify-write sequence. When Station A (processing SKU-4821: fulfilling an order, qty 148→147) and Station B (processing SKU-7533: fulfilling a different order, qty 30→29) both call read from file tFilePath until end of file within the same 2-second window, both read the same 1,200-line snapshot. Station A modifies its in-memory copy: SKU-4821→147. Station B modifies its in-memory copy: SKU-7533→29. Station A writes all 1,200 lines back (SKU-4821=147, SKU-7533=30). Station B — 800ms later — writes all 1,200 lines back from its snapshot: SKU-4821=148 (the original value it read, now 800ms stale), SKU-7533=29. Station A’s decrement of SKU-4821 is silently overwritten. The stock level file now shows 148 when it should show 147. The warehouse has one fewer unit than the system believes.

No error appears anywhere in this sequence. LiveCode produces no error. Windows produces no error. The SMB server produces no error. The file write completes successfully from every workstation’s perspective. Neither operator sees any indication that their transaction conflicted with another. The discrepancy is invisible until the weekly stock audit, when the physical count from the warehouse scanner (147 units) diverges from the system count (148 units). Because the discrepancy is only one unit and involves a SKU that had multiple transactions that morning, the initial assumption is that a receiving operator mis-scanned a quantity. The LiveCode developer spent two weeks confirming that no operator had made a data-entry error before the race condition hypothesis was formed and confirmed by adding diagnostic logging to the updateStockLevel handler that timestamps every read and write operation, then replaying a morning’s log to identify overlapping read-write windows.

LiveCode file I/O architecture and why open file for write does not lock

LiveCode’s file I/O command set maps directly to C standard library fopen calls with specific mode flags. open file tPath for read maps to fopen(path, "rb"): opens the file for reading; on Windows via CreateFile with GENERIC_READ and FILE_SHARE_READ | FILE_SHARE_WRITE. open file tPath for write maps to fopen(path, "wb"): opens the file for writing, truncating to zero length; on Windows via CreateFile with GENERIC_WRITE and FILE_SHARE_READ | FILE_SHARE_WRITE. open file tPath for append maps to fopen(path, "ab"): opens the file for appending, writing only at end-of-file; on Windows via CreateFile with FILE_APPEND_DATA and — critically — FILE_SHARE_READ | FILE_SHARE_WRITE. open file tPath for update maps to fopen(path, "r+b"): opens for both read and write without truncation, positioned at the start of the file.

The critical detail is the dwShareMode parameter. In all four LiveCode file open modes, the underlying Windows CreateFile call uses FILE_SHARE_READ | FILE_SHARE_WRITE, which means any other process (or any other workstation accessing the same file via the SMB share) can also open the file for reading or writing simultaneously. LiveCode provides no built-in mechanism for acquiring an exclusive file lock before a read-modify-write sequence. There is no lock file tPath exclusive command in LiveCode Script. The Windows API does provide advisory byte-range locking via LockFile and LockFileEx, and these can be called from LiveCode via an external (a LiveCode external library that wraps Win32 API calls), but LiveCode’s built-in file I/O commands do not invoke them.

The consequence for any multi-workstation LiveCode deployment that shares a mutable file over an SMB share is that the classic read-modify-write pattern — read the file, modify a value in memory, write the file back — is inherently vulnerable to the lost-update race condition whenever two workstations execute the pattern concurrently. The race window is the duration between the first read from file until end of file and the final close file after the write. For a 1,200-line file on a 100 Mbps LAN, the read takes roughly 10–50ms and the write takes 20–100ms; the total window is 30–150ms per operation. With 5 workstations each processing several orders per minute during a busy receiving shift, the probability that two workstations execute overlapping read-modify-write windows within any given minute is significant. Over an 8-hour shift with 50–100 total inventory updates, 3–5 lost-update collisions per week is consistent with a race window of 100ms and an update rate of 10 updates per minute across 5 stations.

LiveCode, Revolution, MetaCard: the HyperCard lineage

LiveCode’s lineage traces directly to Apple’s HyperCard (1987–2004), one of the most influential software products in personal computing history. HyperCard introduced the stack-and-card metaphor: applications were organized as stacks of cards (analogous to index cards or slides), each card containing fields, buttons, and graphical objects. HyperCard’s scripting language, HyperTalk, was designed by Dan Winkler to read like natural English: put "hello" into field "greeting", go to next card, if the number of items in line 1 of field "data" > 5 then…. HyperTalk’s English-like syntax, combined with HyperCard’s visual card-building interface, made programming accessible to non-programmers for the first time at scale. HyperCard applications — called stacks — were distributed widely in education, medicine, libraries, and small business throughout the late 1980s and 1990s; estimates suggest over 100,000 HyperCard stacks were created.

MetaCard (founded 1992 by Scott Raney) was the first cross-platform HyperCard clone. MetaCard ran on Unix workstations (SunOS, HP-UX, IRIX) and later Linux, implementing a near-complete HyperTalk-compatible scripting language with extensions for Unix system integration. MetaCard stacks were binary-compatible subsets of HyperCard stacks in many respects, and MetaCard introduced revDatabase (a cross-platform database abstraction library supporting SQLite, MySQL, PostgreSQL, and ODBC) years before HyperCard had any comparable data integration. MetaCard also pioneered cross-platform deployment: a single stack file could be authored on one platform and run on others with minimal modification, a feature Apple’s HyperCard could never offer (it was Mac-only throughout its life).

Revolution (2001, RunRev Ltd, founded by Kevin Miller) built on MetaCard’s technology and added a commercial IDE with a more polished authoring environment, multi-platform deployment targets (Windows, macOS, Linux), and a growing standard library. Revolution marketed itself explicitly as “the HyperCard for the 21st century” and attracted a community of HyperCard developers migrating off the platform as Apple allowed HyperCard to stagnate. The Revolution scripting language was a superset of HyperTalk with extensions for modern I/O, regular expressions, XML, and network access. Revolution became the tool of choice for organizations migrating HyperCard stacks to cross-platform deployments in the early 2000s; the wholesale auto parts distributor’s inventory stack was migrated from HyperCard to Revolution in 2003, bringing with it the original HyperCard file I/O pattern for reading and writing the pipe-delimited inventory file — a pattern that worked safely in the single-user Mac-only HyperCard deployment but became a lost-update hazard in the multi-workstation Windows network deployment.

LiveCode (2012, the brand name adopted by RunRev Ltd when the product went open-source) is the current form of the platform. LiveCode Community Edition is licensed under the GPL and is free for open-source projects; LiveCode Enterprise Edition is commercially licensed and required for proprietary commercial applications. LiveCode 9.x (2018–2022) introduced LCB (LiveCode Builder), a statically typed compiled language for authoring LiveCode extensions (widgets and libraries) that can expose platform-native capabilities to LiveCode Script. LiveCode 10.x continued the LCB extension ecosystem and improved Android and iOS deployment. As of 2026, RunRev Ltd continues to develop LiveCode under both Community and Enterprise licenses; the platform is used primarily by organizations with existing LiveCode or Revolution stacks that would be expensive to rewrite, and by a specialist community of cross-platform application developers who value the English-like scripting syntax for rapid development of data-entry and database-fronting applications.

The HyperCard legacy in LiveCode deployments manifests precisely in file I/O patterns. HyperCard’s file access commands — open file, read from file, write to file, close file — were designed for single-user Mac deployments where only one HyperCard session was running at a time and the file was on a local HFS volume. The concept of concurrent multi-user access to a shared file over a network share did not exist in the HyperCard programming model. When HyperCard stacks were migrated to Revolution and then to LiveCode for deployment on Windows networks with SMB shares, the file I/O handlers were typically translated with minimal modification: open file became LiveCode’s open file, the path was changed from a Mac HFS path to a UNC path, and the read-modify-write structure was preserved. The result was a codebase that worked correctly in single-user testing but silently lost updates under concurrent multi-user load — exactly the scenario that appeared in the auto parts distributor’s inventory management stack two decades after the original HyperCard implementation.

The updateStockLevel handler: anatomy of the lost-update

The updateStockLevel handler in the auto parts distributor’s MainInventory.livecode stack looked approximately like this in LiveCode Script:

on updateStockLevel pSKU, pDelta
  put "\\server\inventory\stock_levels.txt" into tFilePath
  open file tFilePath for update
  read from file tFilePath until end of file
  put it into tFileContents
  close file tFilePath
  put empty into tAllLines
  repeat for each line tLine in tFileContents
    put item 1 of tLine into tLineSKU
    if tLineSKU = pSKU then
      put item 2 of tLine + pDelta into item 2 of tLine
    end if
    put tLine & return after tAllLines
  end repeat
  open file tFilePath for write
  write tAllLines to file tFilePath
  close file tFilePath
end updateStockLevel

Note that the handler uses item references (LiveCode’s delimiter-separated chunk expression) where the default item delimiter is comma. The original file used pipe (|) as a delimiter, so the handler would have set set the itemDelimiter to "|" before the repeat loop — a detail omitted above for brevity but present in the actual stack. The critical structural observation is the gap between close file tFilePath (after the read) and open file tFilePath for write (before the write): during the repeat loop, the file is not open. Any other workstation can open the file, read it, modify it, and write it back during the time this station is iterating through 1,200 lines building tAllLines. On a fast workstation processing a simple repeat loop over 1,200 short lines, this gap is 5–20ms. On a workstation under load (antivirus scan, Windows Update, network congestion), this gap can stretch to 100–500ms. In all cases, the gap is nonzero and the file is unlocked.

Even if the handler were restructured to keep the file open across the read-modify-write sequence (not closing after read, then writing), LiveCode’s open file for update and open file for write do not acquire exclusive locks. A second workstation can open the same SMB file simultaneously in both read and write modes because the FILE_SHARE_READ | FILE_SHARE_WRITE share mode permits it. The only way to prevent concurrent writes with LiveCode’s built-in file I/O is to use a separate lock file: before reading, try to create a lock file (e.g., stock_levels.lock) with exclusive access; if the lock file creation fails (another station has it), retry with a backoff; after writing, delete the lock file. This approach works but is fragile — if a workstation crashes between acquiring the lock file and releasing it, the lock file persists indefinitely and blocks all other workstations until manually deleted. The lock file is also not guaranteed to work correctly over all SMB implementations and configurations, because some SMB servers do not support the byte-range locking semantics that LockFileEx relies on across the network.

The fix: per-station delta append log and SQLite via revDatabase

The production fix the LiveCode developer implemented was a per-station delta append log. Instead of reading the entire inventory file and writing it back, each workstation appended a single delta record to its own station-specific delta file:

on logStockDelta pSKU, pDelta
  put "\\server\inventory\deltas\station" & gStationID & ".txt" into tDeltaPath
  put pSKU & "|" & the date & " " & the time & "|" & pDelta & "|station" & gStationID into tDeltaLine
  open file tDeltaPath for append
  write tDeltaLine & return to file tDeltaPath
  close file tDeltaPath
end logStockDelta

Each station writes only to its own delta file. No two stations ever write to the same file. The open file for append operation writes only at end-of-file; even if two processes somehow had the same file open for append simultaneously, each append of a short record (<100 bytes) is serialized at the byte-range level by the Windows SMB server for small writes. There is no in-memory snapshot, no full-file rewrite, no stale read window. A nightly consolidation job (implemented as a LiveCode stack running on a dedicated administrator workstation, triggered by Windows Task Scheduler at 11 PM) reads all 5 station delta files, sorts all delta records chronologically by the timestamp in each line, replays each delta against the master stock_levels.txt file to produce a new reconciled master, archives the station delta files with a date suffix, and creates fresh empty delta files for the next day. Inventory count discrepancies per week: 3–5 → 0.

The delta append log is the minimal-change fix: it preserves the pipe-delimited text file architecture, requires no new software components, and can be implemented with LiveCode’s built-in file I/O commands. For organizations willing to accept a larger scope of change, the more robust fix is SQLite via revDatabase. LiveCode’s revDatabase library provides built-in, no-configuration SQLite access:

put revOpenDatabase("SQLite", "\\server\inventory\stock.db", "", "", "", "") into tConnectionID
if tConnectionID begins with "databaseconnectionid" then
  revExecuteSQL tConnectionID, "UPDATE stock SET qty = qty + :1 WHERE sku = :2", "pDelta", "pSKU"
  revCloseDatabase tConnectionID
end if

SQLite’s Write-Ahead Log (WAL) mode serializes concurrent writes at the database engine level: each UPDATE is an atomic operation protected by SQLite’s internal write lock; two concurrent workstations executing UPDATE stock SET qty = qty + -1 WHERE sku = "SKU-4821" will not produce a lost-update because SQLite serializes the writes at the page level and each update reads and modifies the current value atomically within its transaction. No stale snapshots, no full-file rewrites, no race window. The trade-off is that SQLite WAL mode over SMB shares has known reliability constraints (SQLite documentation explicitly warns against using SQLite database files on SMB/NFS network shares due to broken advisory locking implementations on some NAS devices and SMB server configurations). For the Windows Server 2019 SMB share in this deployment, the SQLite WAL-mode implementation was tested and confirmed reliable; for more demanding concurrent-write scenarios or less reliable SMB environments, MySQL or PostgreSQL via revDatabase are preferable — proper client/server databases that handle concurrent writes correctly regardless of the network file system.

Typical LiveCode developer retainer work and what it looks like in a work log

Lost-update diagnosis in monolithic read-modify-write handlers is the canonical LiveCode invisible production data-loss bug for multi-workstation SMB-deployed stacks. The pattern is consistent: a LiveCode handler reads an entire shared text file into memory (read from file tFilePath until end of file), parses it into a LiveCode array or processes it line-by-line, modifies one value, then writes all lines back (open file tFilePath for write; write tAllLines to file tFilePath). The developer tests the handler on a single workstation — no race condition is possible when only one station runs. In production, 5 workstations each trigger the handler within the same 2-second window during a busy receiving shift; two stations read the same snapshot; each modifies a different value; the later write overwrites the earlier write’s change. No error surfaces on either workstation. The discrepancy appears in the weekly stock audit. Fix: replace open file for write; write tAllLines with open file for append; write tDeltaLine per-station, plus a nightly consolidation job. Inventory discrepancies per week: 3–5 → 0. Work log: “updateStockLevel in MainInventory.livecode; \\server\inventory\stock_levels.txt on Windows Server 2019 SMB; 5 concurrent workstations; Station A (SKU-4821: 148→147) and Station B (SKU-7533: 30→29) both call read from file until end of file within the same 2-second window; Station B writes 800ms after Station A with stale SKU-4821=148 snapshot; Station A’s decrement silently overwritten; inventory discrepancies: 3–5/week; fix: per-station delta append log (station01.txt–station05.txt) + nightly consolidation job; discrepancies after fix: 0; 4h.”

revDatabase SQLite migration for concurrent-write safety is the second most common LiveCode retainer pattern for production data-loss diagnosis. A LiveCode point-of-sale stack for a small retailer stores transaction records in a pipe-delimited text file (\\server\pos\transactions.txt) appended after each sale with open file tPath for append; write tLine & return to file tPath; close file tPath. Append-only writes are generally safe for concurrent stations — appending a short line is serialized at the SMB level. But the stack also maintains a running daily totals file (daily_totals.txt), updated with a read-modify-write pattern after each sale to track the current day’s revenue and transaction count. With 3 POS terminals processing sales concurrently during peak hours, the daily totals file experiences 2–3 lost-update collisions per day, typically during a rush when all 3 terminals ring up sales within the same 5-second window. Fix: migrate daily_totals.txt to a SQLite database via revDatabase, replacing the read-modify-write pattern with an atomic UPDATE daily_totals SET revenue = revenue + :1, txn_count = txn_count + 1 WHERE date = :2. Daily totals discrepancies: 2–3/day → 0. Work log: “updateDailyTotals in POSMain.livecode; \\server\pos\daily_totals.txt; 3 concurrent POS terminals; read-modify-write pattern; 2–3 lost-update collisions per day during peak hours; fix: revDatabase SQLite migration; revOpenDatabase("SQLite", "\\server\pos\pos.db", ...); revExecuteSQL atomic UPDATE; collisions after fix: 0; 3h.”

LiveCode stack crash diagnosis from unhandled errors in file I/O handlers is the third common LiveCode retainer pattern. A LiveCode 9 asset management stack for a design studio opens a project index file (/Volumes/NAS/projects/index.txt) on a macOS NFS-mounted NAS share. Occasionally — roughly once per week — the stack crashes with a LiveCode error dialog (“The application has encountered a problem”) during the open file tPath for update call. The NAS share briefly disconnects during NFS renegotiation (the NAS is set to a 15-minute idle timeout); during the reconnect window, the open file for update call fails with an OS error that LiveCode surfaces as an error in the result. The handler does not check if the result is not empty then after the open file call; the subsequent read from file tPath until end of file call references a file that was never successfully opened, producing an invalid file handle error that LiveCode escalates to an unhandled exception, crashing the stack. Fix: add if the result is not empty then (exit updateProjectIndex / report error) after every open file call; add a retry loop (up to 3 attempts with a 2-second wait between attempts) for transient network errors. Stack crashes per week from NFS reconnect: 1–2 → 0. Work log: “updateProjectIndex in AssetManager.livecode; /Volumes/NAS/projects/index.txt on macOS NFS mount; NAS 15-minute idle timeout triggers NFS renegotiation; open file for update fails; unhandled error in the result; subsequent read from file crashes stack; fix: if the result is not empty then exit after every file open; 3-attempt retry loop with 2s wait; crashes after fix: 0; 2h.”

Track LiveCode developer retainer hours without the status emails

When a 4-hour investigation traces 3–5 silent inventory count discrepancies per week to a LiveCode updateStockLevel handler that reads the entire shared pipe-delimited file into memory, modifies a SKU quantity, then writes all 1,200 lines back without an exclusive lock — two concurrent workstations reading the same snapshot within an 800ms window; the later write overwriting the earlier decrement; the warehouse showing one fewer unit than the system believes — the work log must name the handler, the file path, the pair of workstation SKU updates that collided, the stale-snapshot write interval, and the inventory discrepancies per week before and after the fix. HourTab gives your LiveCode retainer client a public dashboard URL they can bookmark: hours used, hours remaining, and a work log naming the delta-append-log fix. No client login. No status emails. CSV in, URL out.

See HourTab pricing →

How HourTab tracks LiveCode developer retainer hours

LiveCode lost-update bugs are invisible by the same mechanism that makes them undetectable in single-workstation development testing: when one station calls open file tFilePath for write; write tAllLines to file tFilePath; close file tFilePath, the write completes successfully, the file now reflects the correct updated value, and the handler returns without error. The developer verifies the change in the file and confirms the handler works. In production, the race occurs only when two stations execute overlapping read-modify-write sequences — a condition that requires simultaneous load from at least two stations, which does not occur in typical development or QA environments. The diagnostic artifact is the weekly stock audit report, which shows a count discrepancy between the physical warehouse count and the system count. Without correlated timestamps from the updateStockLevel handler, there is no way to distinguish a lost-update collision from an operator data-entry error.

The work log must name the mechanism to be auditable: which LiveCode stack (MainInventory.livecode), which handler (updateStockLevel), which file path (\\server\inventory\stock_levels.txt on Windows Server 2019 SMB), which pair of stations (Station A processing SKU-4821: qty 148→147; Station B processing SKU-7533: qty 30→29), the read-overlap window (both stations call read from file until end of file within the same 2-second window), the stale-snapshot write (Station B writes 800ms after Station A; Station B’s snapshot has SKU-4821=148, the pre-Station-A value; Station A’s decrement is overwritten), the inventory discrepancies per week before fix (3–5), the discrepancies after fix (0), and the fix (per-station delta append log: 5 station files in \\server\inventory\deltas\; each station appends a pipe-delimited delta record with SKU, timestamp, delta quantity, and station ID; nightly consolidation job sorts by timestamp and replays all deltas against stock_levels.txt). A log entry that says “fixed inventory sync issue, 4h” is not auditable. A log entry that names the handler, the file, the concurrent stations, the stale-snapshot mechanism, the lost-update window, and the delta-append-log fix is auditable and defensible to the distributor’s inventory manager and the retainer contract scope. HourTab gives LiveCode developers a public retainer-hours URL they send to clients — wholesale distributors, retailers, healthcare practices, legal firms, and small manufacturers that built multi-user desktop applications in HyperCard, Revolution, or LiveCode in the 1990s and 2000s, maintained today by the original developer or a successor retainer consultant.

Comparative context: LiveCode lost-update bugs are structurally related to the same family of concurrent file-write race conditions that appear across legacy desktop application platforms deployed over network shares. HyperCard retainers cover the same HyperTalk-family file I/O model — HyperCard’s open file, read from file, write to file commands have the same single-user-era design assumptions, producing the same lost-update vulnerability when HyperCard stacks are deployed over AppleShare or AFP shares with multiple Mac workstations. ToolBook retainers cover the same OS-level exclusive file lock pattern: ToolBook’s FileOpen acquires an exclusive Windows file lock that blocks concurrent FileOpen calls from other stations, producing “File in use” errors rather than silent lost updates — a different symptom from the same multi-user file-sharing deployment pattern. WinDev retainers cover HFSQL HLock file-system lock not released on validation failure branch — same resource-lifecycle misunderstanding as LiveCode’s file-open-without-exclusive-lock, same post-deployment analytics audit as the discovery mechanism for a concurrency bug that is invisible in single-user testing.

LiveCode Community Edition vs. Enterprise Edition: retainer contract implications

A LiveCode retainer contract must specify which edition of LiveCode is in use, because the licensing model has direct implications for what the retainer developer can legally deliver. LiveCode Community Edition is licensed under the GNU General Public License v3 (GPL). Under GPL, any application distributed to users that incorporates LiveCode Community Edition source code must itself be released under a GPL-compatible open-source license and make its source code available to recipients. For internal-only deployments — where the LiveCode stack runs on workstations owned by the organization that built it and is never distributed to third parties — the GPL source-release requirement typically does not apply (because internal deployment is not “distribution” under GPL). For the wholesale auto parts distributor’s internal inventory management stack, Community Edition is legally usable under the internal-use interpretation. However, if the distributor ever wanted to share the stack binary with a customer, vendor, or partner, that distribution would trigger the GPL source-release requirement.

LiveCode Enterprise Edition is commercially licensed (annual subscription per developer seat, as of 2026) and places no GPL restrictions on the applications built with it. Enterprise Edition is required for commercial software products, customer-facing applications, applications distributed to clients, and applications embedded in commercial products. Enterprise Edition also includes priority support from RunRev Ltd, access to pre-release builds, and additional deployment options for mobile (iOS and Android) and server targets. A retainer agreement for a LiveCode developer maintaining a commercially distributed application must specify that the developer is working under a valid Enterprise Edition license; using Community Edition to build or maintain a commercially distributed proprietary application is a GPL violation.

The retainer agreement should also specify which LiveCode version is the target. LiveCode 9.6.x and 10.x use different internal stack file formats and have different compatibility characteristics with older Revolution or LiveCode 6/7/8 stacks. LiveCode Builder (LCB) extensions compiled for one major version are not binary-compatible with other major versions; an LCB widget compiled for LiveCode 9 must be recompiled for LiveCode 10. If the retainer scope includes LCB extension development or maintenance, the agreement should specify the target LiveCode version and the build toolchain required. For retainers covering stacks that have not been updated since LiveCode 6 or 7 (the era of the Revolution-to-LiveCode branding transition), the agreement should explicitly scope whether the retainer developer is responsible for upgrading the stack to a current LiveCode version or only for maintaining it under the existing version — because version upgrades sometimes require handler syntax changes (particularly around Unicode string handling, which changed significantly between LiveCode 7 and 9) that are not backward-compatible with the original code.

Logging LiveCode retainer hours: rates, scope, and HourTab

LiveCode retainer rates reflect the specialist nature of the platform and the depth of expertise required to diagnose production bugs that are invisible in development. Entry-level LiveCode developers — those with experience in LiveCode Script handler and function syntax, LiveCode card and stack navigation, basic file I/O, and standard form controls — typically bill at $50 to $90 per hour. Mid-level LiveCode developers — those with experience in LiveCode array manipulation, revDatabase SQLite and MySQL integration, LiveCode server-side scripting, and multi-user concurrency issues (lost-update diagnosis, delta append log design, lock file patterns) — typically bill at $80 to $145 per hour. Senior LiveCode developers — those with deep knowledge of LiveCode 9.x and 10.x LCB extension development, cross-platform deployment for Windows, macOS, Linux, iOS, and Android, HyperCard/Revolution/LiveCode migration forensics, and production diagnosis of silent data-loss bugs in SMB-deployed stacks — typically bill at $120 to $210 per hour. Monthly retainer ranges: $1,500 to $3,000 per month for advisory engagements covering file I/O concurrency audits and revDatabase migration planning; $2,500 to $5,000 per month for active maintenance of multi-platform LiveCode application deployments across Windows, macOS, and mobile targets.

The pricing reflects real scarcity: the number of developers with production LiveCode deployment experience — specifically, experience diagnosing the concurrency bugs that emerge from HyperCard-era file I/O patterns in multi-user Windows network environments — is small and not growing. LiveCode is not taught in computer science programs; the developer community is self-trained and largely composed of people who started with HyperCard or Revolution. Organizations with LiveCode deployments typically have one or two people who understand the stack architecture, often the original developer or a developer who was trained by them. A retainer relationship with a senior LiveCode developer represents access to diagnostic expertise that cannot be replicated by a generalist developer hired off a job board. Communicating that value to a client requires logging retainer work with enough technical precision that the client can see what was investigated, what was found, and what was fixed — not just hours billed.

HourTab is designed for exactly this communication pattern. A LiveCode retainer developer exports their time-tracker CSV, uploads it to HourTab, and sends their client a public dashboard URL. The client bookmarks the URL. Every time they wonder how many hours remain in the retainer or what those hours were spent on, they visit the URL — no login, no portal, no status email request. The work log shows each session with the handler name, the file path, the concurrent stations, the lost-update mechanism, the discrepancies before and after the fix. The client sees the value of the retainer in the work log. The developer stops spending retainer hours on client status communication.

FAQ: LiveCode developer retainers

What does a LiveCode developer on retainer typically do?

A LiveCode developer on monthly retainer covers lost-update audits (reviewing every handler that opens a shared file, reads it into memory, modifies a value, and writes it back, to confirm whether a concurrent workstation can open the same file during the read-modify-write window); concurrent inventory discrepancy diagnosis (correlating weekly stock audit reports, SMB access logs, and handler timestamps to identify which SKUs experienced silent lost-update collisions and which pair of workstations triggered them); delta append log implementation (replacing monolithic full-file rewrite handlers with per-station append-only delta files and nightly consolidation jobs); SQLite migration via revDatabase (replacing text file I/O with atomic revExecuteSQL UPDATE calls that eliminate the lost-update race entirely); and LiveCode stack modernization including LCB extension development, Community-to-Enterprise Edition license migration, and LiveCode 9.x to 10.x upgrade path planning for stacks with deprecated handler syntax.

What LiveCode application deployment bug work is most commonly underlogged?

Lost-update from monolithic read-modify-write on a shared SMB text file — where a LiveCode handler reads an entire pipe-delimited inventory file into memory with open file for update; read from file until end of file, modifies one SKU quantity, then writes all lines back with open file for write; write tAllLines to file without acquiring an exclusive lock; two concurrent workstations read the same snapshot within the same 2-second window; each modifies a different SKU; the later write overwrites all lines from its stale snapshot; one inventory count adjustment is silently lost — is the most systematically underlogged LiveCode retainer work. The developer who tests the handler on one workstation never triggers the race; the silent lost-update surfaces only during the weekly stock audit. The work log must name the LiveCode handler, the file path, the pair of SKU updates that collided, the stale-snapshot write interval, and the inventory discrepancies per week before and after the fix.

What are typical LiveCode developer retainer rates?

Entry-level LiveCode developers with experience in LiveCode Script handler syntax, card and stack navigation, basic file I/O, and form controls typically bill at $50 to $90 per hour. Mid-level LiveCode developers with experience in array manipulation, revDatabase SQLite and MySQL integration, LiveCode server scripting, and multi-user concurrency diagnosis typically bill at $80 to $145 per hour. Senior LiveCode developers with deep knowledge of LCB extension development, cross-platform deployment, HyperCard/Revolution/LiveCode migration forensics, and production diagnosis of silent data-loss bugs in SMB-deployed stacks typically bill at $120 to $210 per hour. Monthly retainer ranges: $1,500 to $3,000 per month for advisory engagements covering file I/O concurrency audits and revDatabase migration planning; $2,500 to $5,000 per month for active multi-platform LiveCode application maintenance.

What should a LiveCode developer retainer agreement include?

A LiveCode developer retainer agreement should specify: LiveCode version (9.6.x, 10.x) and edition (Community Edition under GPL or Enterprise Edition under commercial license — Community Edition restricts commercial distribution); deployment model (standalone desktop stack on Windows, macOS, or Linux; iOS or Android mobile app; LiveCode Server for web deployment); whether the developer has access to the LiveCode IDE to open and edit the .livecode stack source file (required for handler modifications — deployed binaries are not editable); multi-user deployment context (number of concurrent workstations; whether shared data files are accessed over SMB or NFS — determines whether lost-update concurrency analysis is in scope); data storage model (pipe-delimited or CSV text files, SQLite via revDatabase, MySQL via revDatabase, or ODBC — determines file-locking or transaction audit scope); whether the retainer covers per-station delta append log migration or revDatabase SQLite migration; and whether the retainer covers LCB extension development, LiveCode Builder widget authoring, or cross-platform build pipeline maintenance for iOS/Android targets.

How should LiveCode developer retainer hours be logged?

Log each LiveCode retainer session with the handler name, the file path, the concurrent workstations, and the inventory outcome. For lost-update diagnosis: handler (updateStockLevel in MainInventory.livecode), file path (\\server\inventory\stock_levels.txt on Windows Server 2019 SMB), workstation pair (Station A: SKU-4821 qty 148→147; Station B: SKU-7533 qty 30→29), read-overlap window (both stations within the same 2-second window), stale-snapshot write (Station B writes 800ms after Station A; Station B’s snapshot has SKU-4821=148; Station A’s decrement overwritten), discrepancies per week before fix (3–5), discrepancies after fix (0), fix (per-station delta append log + nightly consolidation job), hours (4h). For revDatabase SQLite migration: handler, original file path, SQLite database path, revOpenDatabase call, revExecuteSQL atomic UPDATE with parameterized query, lost-update collisions before migration (3–5/week), collisions after (0), hours. For NFS crash diagnosis: handler, file path, NFS timeout interval, open file failure path, unhandled error in the result, fix (error check after every file open + retry loop), crashes per week before and after, hours.