Blog › ICP guides

occam developer on retainer: Transputer systems programming, CSP channel lexical scope, PAR and SEQ composition, and occam language on monthly retainer

October 1, 2026 · ~15 min read

An occam developer was writing a pipeline of parallel processes for an INMOS Transputer application. The pipeline consisted of an upstream process that produced data and a downstream process that consumed it, connected by a channel. The developer wrote the pipeline using a combination of SEQ and PAR constructs: a SEQ block set up initial state and declared the channel connecting the two pipeline stages, and a PAR block inside the SEQ ran the upstream and downstream processes. The CHAN declaration was inside the SEQ block, syntactically before the PAR block. The developer expected that the channel declared in SEQ would be visible to both processes inside the PAR block. occam channels have lexical scope: a CHAN declared inside a SEQ block is in scope only for code syntactically nested within that SEQ block — the PAR block is a sibling of the channel declaration, not a child of it, so the channel is not in scope for the processes inside PAR. The compiler produced a scope error. Scope errors: 2. Fix: moved the CHAN declarations to the outer lexical scope that enclosed both the SEQ setup block and the PAR block. Channel declarations in the outer scope are visible to all code nested inside, including both the SEQ and PAR blocks. Scope errors: 2 → 0.

The work log said “fixed channel scope errors, relocated CHAN declarations, 5h.” It cannot explain the mechanism: that occam channels have strict lexical scope rules enforced by the compiler, that a CHAN declaration inside SEQ is not syntactically visible to sibling PAR processes because they are not nested within the SEQ block, that the correct architecture requires the channel declaration to be at the scope level that encloses all processes that use the channel, or that diagnosing the scope error required understanding occam’s indentation-based block structure and the relationship between the SEQ and PAR blocks in the lexical nesting hierarchy. A client reading that entry sees five hours for what sounds like moving a variable declaration two lines up in the source file. What is invisible is the structural analysis: mapping the lexical nesting tree, identifying the shallowest scope that encloses all processes using the channel, and verifying that the relocation did not change the semantics of any initialization that was performed on the channel before the PAR block ran.

occam language overview: CSP as a Transputer language

occam was designed by David May at INMOS in 1983, based directly on Tony Hoare’s Communicating Sequential Processes (CSP) formalism. INMOS was building the Transputer, a microprocessor specifically designed for massively parallel computing: each Transputer had four serial hardware links that connected to adjacent Transputers, and the hardware was designed for programs written as networks of communicating processes mapped one-to-one to Transputer processors. occam was the programming language that made this hardware model practical: a program written in occam as a set of processes communicating over channels could be compiled directly to a Transputer network, with each occam process assigned to one Transputer and each occam channel corresponding to a hardware link between Transputers (for inter-Transputer channels) or a software channel within a single Transputer (for channels between processes on the same Transputer).

occam is one of the earliest implementations of CSP as a programming language, predating all other members of the CSP language family: Newsqueak (1988), Limbo (1995), Alef (1992), Go (2009). The core semantic features that all these languages share — synchronous rendezvous channels, parallel composition, non-deterministic guarded selection — were first given a practical programming language form in occam. occam’s syntax uses indentation rather than braces to delimit blocks (like Python, but predating it), and its keywords are uppercase identifiers rather than lowercase. The CSP faithfulness of occam’s design makes it a reference implementation for understanding the CSP channel model at its purest: no garbage collection, no dynamic allocation, no closures, no first-class functions. Just processes, channels, and the three composition operators SEQ, PAR, and ALT.

occam retainer work today covers INMOS Transputer systems still in operation (primarily embedded systems and signal processing hardware where the Transputer was deployed in the 1980s and 1990s and has been running continuously since), academic research using occam for formal verification of concurrent systems, and occam2.1 and occam-pi (a Pi-calculus extension) for modern parallel computing research. The Transputer hardware and occam toolchain are maintained by a small community; expertise in occam represents both programming language knowledge and embedded systems knowledge specific to the Transputer architecture.

Channel lexical scope: the structural rule that causes scope errors

occam’s channel scope rule is a direct consequence of its block-structured, indentation-based syntax. In occam, everything is a process, and processes are nested using SEQ, PAR, and ALT as structural combinators. Declarations — including CHAN declarations — are visible to all code nested within the block they appear in, and not visible outside that block.

A CHAN OF INT pipeline: declaration inside a SEQ block is at the same nesting level as the statements that follow in the SEQ block. If the SEQ block contains, among other statements, a PAR block that lists two processes, those processes are nested inside the PAR block which is nested inside the SEQ block. The channel declaration is a sibling of the PAR block in the SEQ block’s body, not a parent of the processes inside PAR. Specifically:

SEQ
  CHAN OF INT pipeline:
  -- pipeline is in scope here
  PAR
    upstream(pipeline) -- compiler error: pipeline not in scope
    downstream(pipeline) -- compiler error: pipeline not in scope

The compiler error occurs because the processes upstream and downstream inside the PAR block are not syntactically within the scope of the CHAN OF INT pipeline: declaration. The declaration is at the level of the SEQ block, making it visible to all statements in the SEQ block at the same level as the PAR statement itself. However, the PROC bodies (upstream and downstream) are separate PROC definitions whose channel parameters determine their visible channels. The call site passes pipeline as an argument, but pipeline is out of scope at the call site inside PAR.

The fix is to move the CHAN declaration to the outer scope that encloses both the SEQ setup block and the PAR block. In occam programs, this typically means placing CHAN declarations at the outermost level of the enclosing PROC or program, before the first SEQ or PAR statement. All processes in all PAR blocks within that scope can then use the channel by passing it as a parameter.

PAR and SEQ: the composition operators that structure occam programs

occam has three fundamental process composition operators, each with precise semantic content:

SEQ { P1; P2; ... } runs processes sequentially. Each process in the SEQ body starts when the previous process terminates. The SEQ block terminates when the last process in its body terminates. Sequential composition is used for initialization sequences, for stages within a process that have data dependencies, and for any computation where order of execution matters. Variables and channels declared inside a SEQ block are in scope for all subsequent statements in that block.

PAR { P1; P2; ... } runs processes in parallel. All processes in the PAR body start simultaneously. The PAR block terminates when all its child processes terminate. Processes in a PAR block communicate only through channels that are in scope for all of them; there is no shared memory between parallel processes in occam. In a Transputer implementation, each process in a PAR block can be assigned to a separate Transputer processor, with channels between them implemented as hardware links.

ALT { WHEN g1 c1 ? x: P1; WHEN g2 c2 ? x: P2; ... } selects among a set of guarded input processes. Each alternative is a guard condition (Boolean) combined with a channel receive; the ALT evaluates all guards and waits for a ready communication on one of the channels whose guard is true. When a communication becomes available on one such channel, the ALT commits to that alternative and executes its body. The selection is non-deterministic when multiple guarded alternatives are simultaneously ready. The ALT is the occam equivalent of Newsqueak’s select, Limbo’s alt, and Alef’s alt { }, and implements Hoare’s original CSP external choice operator.

Transputer topology: mapping occam processes to hardware

The INMOS Transputer has four bidirectional serial hardware links, each capable of running at 5, 10, or 20 Mbaud. Each link is a point-to-point connection to one adjacent Transputer. A Transputer network is a graph of Transputer nodes connected by links, and the network topology — pipeline, tree, ring, torus, mesh, or custom — is determined by the physical hardware connections. occam programs running on a Transputer network assign processes to specific Transputers and map occam channels to specific hardware links using the occam placement and routing configuration.

For occam channels that connect processes on the same Transputer, communication is a software operation: the Transputer’s internal channel mechanism handles the synchronous rendezvous in hardware-assisted shared memory. For occam channels that connect processes on different Transputers, communication uses the hardware serial links: data is serialized and transmitted over the link, which is a hardware operation with fixed bandwidth. The bandwidth constraint on hardware links is a critical design parameter for Transputer occam programs: a channel that carries more data per unit time than the link can support becomes a bottleneck, and the entire pipeline backs up due to synchronous rendezvous blocking the sender.

Retainer work on Transputer topology involves analyzing the data flow rates in the occam program, determining the bandwidth requirements for each inter-Transputer channel, mapping those requirements against the available link bandwidths, and redesigning the process decomposition or the Transputer network topology when the mapping is infeasible. A common optimization is restructuring a linear pipeline into a tree or torus to increase aggregate bandwidth, at the cost of more complex routing logic in the occam processes.

ALT guarded selection: liveness and starvation in occam

The ALT construct’s non-deterministic selection creates a liveness risk: if one guarded alternative is always ready when the ALT evaluates, that alternative may be selected every time, starving other alternatives indefinitely. This is a liveness failure: a communication that should eventually be delivered is never selected. The classic occam pattern is an ALT with one high-rate data channel and one low-rate control channel; if the data channel always has data available when the ALT evaluates, the control channel is never selected and control messages are never processed.

occam provides a priority variant, PRI ALT, that selects the highest-priority ready alternative rather than selecting non-deterministically. PRI ALT solves some liveness problems (the control channel can be given higher priority than the data channel, ensuring control messages are always processed first when available) but introduces others (if the control channel is always ready, the data channel is never selected). The correct liveness design depends on the specific communication pattern: whether the control and data channels have incomparable rates, whether the channels are mutually exclusive in practice, and whether the ordering semantics of PRI ALT matches the intended semantics of the system.

Retainer work on ALT liveness requires analyzing the readiness patterns of all alternatives under the expected communication load, identifying which combinations of simultaneous readiness are possible, and determining whether the non-deterministic (or priority) selection policy produces the required liveness properties under those patterns. This analysis is often done using occam’s CSP-based formal model: representing the processes as CSP specifications, composing them, and using CSP tools (FDR, ProB) to check liveness and safety properties.

Typical occam retainer work and what it looks like in a work log

An occam retainer typically covers three recurring categories of work. The first is channel scope audit: systematically reviewing all CHAN declarations to confirm that each declaration is at the correct lexical scope level for all processes that use the channel. A codebase with many nested SEQ and PAR blocks requires methodical scope tracing to identify declarations that are at too shallow a scope (not visible to some processes that need the channel) or too deep a scope (declared inside a block that runs only once, but used by a process that runs repeatedly). Work log entry: “channel scope audit: 47 CHAN declarations reviewed, 3 at incorrect scope level, 2 promoted to outer PAR scope, 1 to outermost PROC scope; scope errors: 2 → 0; 5h.” Without the scope rule context, the entry reads as fixing two compiler errors by moving declarations.

The second category is PAR decomposition design. An occam program for a Transputer network must decompose the computation into concurrent PROC instances with the correct channel topology: each PROC takes its channels as parameters, and the PAR block at the top level assembles the network by calling the PROCs with the appropriate channel arguments. Designing this decomposition requires understanding the data flow (which data flows from which source to which sink), the concurrency structure (which computations can run in parallel), and the channel topology (which processes communicate and in which direction). Work log entry: “PAR decomposition for 6-stage signal processing pipeline: 6 PROC instances, 5 pipeline channels designed; CHAN declarations promoted to outer scope; Transputer link assignment: stages 1 and 2 on T1, 3 and 4 on T2, 5 and 6 on T3; inter-Transputer channels: link 0 T1-T2, link 1 T2-T3; bandwidth analysis: 12 MB/s required per link, within 20 Mbaud hardware limit; 9h.”

The third category is ALT liveness analysis. Identifying starvation-prone ALT patterns requires load analysis: simulating the readiness rates of each alternative and checking whether non-deterministic selection produces fair service. In practice this is done by inserting per-alternative counters in a test harness and running the program under the expected load profile. Retainer work produces a fairness specification alongside the occam code, making the expected selection frequencies explicit so that future modifications to the communication load can be assessed against the liveness requirements. Work log entry: “ALT liveness analysis on 3 ALTs in control loop: data channel selected 98.7% of time under full load, control channel starved; converted to PRI ALT with control channel at priority 0; control channel selection rate: 0% → 100% when available; fairness specification documented; 7h.”

Track occam developer retainer hours without the status emails

When a five-hour session traces occam channel scope errors to CHAN declarations inside SEQ blocks that are not in lexical scope for sibling PAR processes, moves the declarations to the outer scope, and verifies that scope errors drop from 2 to 0, the work log needs to say that — not just “fixed channel declarations.” HourTab gives your occam retainer client a public dashboard URL they can bookmark: hours used, hours remaining, and a work log that names the lexical scope rule, the SEQ/PAR nesting structure, and the scope errors before and after. No client login. No status emails. CSV in, URL out.

See HourTab pricing →

How HourTab tracks occam developer retainer hours

occam retainer work is invisible by the same mechanism that makes occam’s scope rules precise: the lexical scope structure is a property of the code’s indentation-based nesting, not of any visible runtime behavior. A client who sees “5h — fixed channel scope errors” cannot assess whether five hours was proportionate to what sounds like moving two lines up in the source file. The work log needs to say: CHAN declarations were inside SEQ block at line N; PAR block at line M is a sibling, not a child, of the SEQ block; processes inside PAR could not see channels declared inside SEQ; compiler reported scope error at line N+3 (upstream call site) and N+4 (downstream call site); lexical nesting tree traced to identify correct outer scope; declarations promoted to outer PROC scope at line K; both process calls now resolve channel in scope; scope errors: 2 → 0. That log entry is auditable and justifies the hours by showing the lexical scope rule, the nesting tree analysis, and the structural relocation.

HourTab gives occam developers a public retainer-hours URL they send to clients — typically organizations maintaining INMOS Transputer systems in embedded signal processing or parallel computing applications, academic research groups using occam for concurrent systems formal verification, and developers working on occam-pi or other occam extensions for modern parallel computing. For occam retainers, each work log entry should name the mechanism at the level of CSP: which channel declaration had incorrect scope, which PAR processes needed access, what the lexical nesting structure was, and whether the fix required scope promotion or process parameter redesign. Comparative context for scope discussions: occam retainer work has conceptual overlap with retainer work on Newsqueak, Limbo, Alef, and Pict — all CSP-family channels with synchronous rendezvous. occam is the oldest of the family and the most hardware-coupled; senior occam expertise commands $148 to $268 per hour because the combination of CSP language knowledge, Transputer hardware architecture, formal verification methods, and decades of operational embedded systems is extremely rare.

FAQ: occam developer retainers

What does an occam developer on retainer typically do?

An occam developer on monthly retainer covers channel lexical scope (CHAN OF TYPE name declares channel; scope rule: visible only in lexically nested code; SEQ-declared channel not in scope for sibling PAR processes; fix: promote to outer enclosing scope); PAR and SEQ composition (SEQ: sequential composition; PAR: parallel, terminates when all children terminate; CHAN declarations in PAR scope visible to all children; no shared memory between PAR processes); ALT guarded selection (ALT { WHEN g c ? var: P }; non-deterministic when multiple guards true and channels ready; PRI ALT for priority selection; liveness analysis for starvation under asymmetric load); PROC declarations (PROC name(CHAN OF TYPE c, ...) body; channels as parameters; no global state); and Transputer topology (process-to-processor mapping; hardware link channels; bandwidth constraints; network topology design for pipeline, tree, ring).

What occam work is most commonly underlogged in a retainer?

Channel scope audit (all CHAN declarations reviewed; declarations at incorrect scope identified; promotions required; 5 to 8 hrs invisible); PAR decomposition design (PROC instances; channel topology; Transputer assignment; bandwidth analysis; 6 to 10 hrs invisible); ALT liveness analysis (guard readiness rates; starvation identification; PRI ALT conversion; fairness specification; 4 to 7 hrs invisible); Transputer topology design (link assignment; bandwidth analysis; pipeline vs tree vs ring tradeoffs; 5 to 9 hrs invisible); and WHILE termination analysis (termination condition; channel drain design; sentinel protocol; 4 to 7 hrs invisible).

What are typical occam developer retainer rates?

Entry-level occam developers with 1 to 2 years covering channel model basics, PAR and SEQ composition, and CSP fundamentals typically bill at $65 to $120 per hour. Mid-level occam programmers with 2 to 4 years covering channel scope diagnosis, PAR decomposition design, ALT liveness analysis, and Transputer topology typically bill at $100 to $180 per hour. Senior occam language developers with 4 or more years covering advanced Transputer network design, CSP formal verification, pipeline optimization, and occam language theory typically bill at $148 to $268 per hour. Monthly retainer ranges: $2,000 to $3,500 per month for advisory engagements (15 to 25 hours per month); $4,000 to $11,500 per month for full engagement occam development on Transputer systems.

What should an occam developer retainer agreement include?

An occam developer retainer agreement should specify: channel scope audit scope (CHAN declarations reviewed; promotions in scope; scope errors acceptable per module); PAR decomposition scope (processes designed; channel topology; Transputer assignment; bandwidth analysis); ALT scope (liveness analysis scope; starvation redesign; fairness criteria); Transputer topology scope (links analyzed; topology redesign; capacity planning); and hour logging format (scope error: CHAN location, PAR processes needing access, scope promotion applied, errors before and after; PAR decomposition: PROC count, channels, Transputer assignment, bandwidth; ALT: guard conditions, starvation analysis, PRI ALT applied; Transputer: links, bandwidth, topology).

How should occam developer retainer hours be logged?

Log each occam retainer session with: channel scope category (CHAN declaration: name, type, original location: inside SEQ at line N; PAR processes using it: P1 at line M, P2 at line M+2; scope error: compiler message; outer scope level identified: enclosing PROC at line K; declaration promoted to line K+1; scope errors before: 2; after: 0); PAR composition category (PAR block: process list; channels: name, direction, type; PROC interfaces: parameters; data flow verified; independence: no shared state; Transputer assignment: process, Transputer index, hardware links); ALT category (ALT location; alternatives: channel, guard, body; starvation analysis: which guard always true; fix: PRI ALT or guard redesign; selection rate before: data 98.7%, control 0%; after: data N%, control 100% when available; liveness: all alternatives eventually selected); Transputer category (link channels: name, direction, Transputers connected; bandwidth: messages/sec required vs Mbaud available; topology: type, justification); and for all categories the before and after count of compiler scope errors and runtime deadlock events per test cycle).