| layout | default |
|---|---|
| title | Chapter 2: Architecture and Monorepo Layout |
| nav_order | 2 |
| parent | HumanLayer Tutorial |
Welcome to Chapter 2: Architecture and Monorepo Layout. In this part of HumanLayer Tutorial: Context Engineering and Human-Governed Coding Agents, you will build an intuitive mental model first, then move into concrete implementation details and practical production tradeoffs.
HumanLayer uses a monorepo layout that supports multiple workflow surfaces and tooling paths.
| Area | Focus |
|---|---|
apps/ |
end-user application surfaces |
packages/ |
reusable shared libraries |
| docs and scripts | workflow guidance and automation |
CLI-related dirs (hld, hlyr) |
command workflows and tooling |
You now know where to inspect and extend key parts of the HumanLayer codebase.
Next: Chapter 3: Context Engineering Workflows
The processStream function in hack/visualize.ts handles a key part of this chapter's functionality:
}
async function processStream() {
const rl = createInterface({
input: process.stdin,
crlfDelay: Infinity,
});
const debugMode = process.argv.includes('--debug');
const toolCalls = new Map(); // Store tool calls by their ID
const pendingResults = new Map(); // Store results waiting for their tool calls
let lastLine = null; // Track the last line to detect final message
let isLastAssistantMessage = false;
rl.on('line', (line) => {
if (line.trim()) {
const timestamp = debugMode
? `${colors.dim}[${new Date().toISOString()}]${colors.reset} `
: '';
try {
const json = JSON.parse(line);
// Check if this is a tool call
if (json.type === 'assistant' && json.message?.content?.[0]?.id) {
const toolCall = json.message.content[0];
const toolId = toolCall.id;
// Store the tool call
toolCalls.set(toolId, {
toolCall: json,
timestamp: timestamp,This function is important because it defines how HumanLayer Tutorial: Context Engineering and Human-Governed Coding Agents implements the patterns covered in this chapter.
The displayToolCallWithResult function in hack/visualize.ts handles a key part of this chapter's functionality:
if (pendingResults.has(toolId)) {
const result = pendingResults.get(toolId);
displayToolCallWithResult(
toolCall,
json,
result.toolResult,
result.timestamp,
timestamp
);
pendingResults.delete(toolId);
} else {
// Display the tool call and mark it as pending
process.stdout.write(`${timestamp + formatConcise(json)}\n`);
process.stdout.write(`${colors.dim} ⎿ Waiting for result...${colors.reset}\n\n`);
}
}
// Check if this is a tool result
else if (json.type === 'user' && json.message?.content?.[0]?.type === 'tool_result') {
const toolResult = json.message.content[0];
const toolId = toolResult.tool_use_id;
if (toolCalls.has(toolId)) {
// We have the matching tool call, display them together
const stored = toolCalls.get(toolId);
displayToolCallWithResult(
stored.toolCall.message.content[0],
stored.toolCall,
json,
stored.timestamp,
timestamp
);
toolCalls.delete(toolId);This function is important because it defines how HumanLayer Tutorial: Context Engineering and Human-Governed Coding Agents implements the patterns covered in this chapter.
The UnmarshalJSON function in claudecode-go/types.go handles a key part of this chapter's functionality:
}
// UnmarshalJSON implements custom unmarshaling to handle both string and array formats
func (c *ContentField) UnmarshalJSON(data []byte) error {
// First try to unmarshal as string
var str string
if err := json.Unmarshal(data, &str); err == nil {
c.Value = str
return nil
}
// If that fails, try array format
var arr []struct {
Type string `json:"type"`
Text string `json:"text"`
}
if err := json.Unmarshal(data, &arr); err == nil {
// Concatenate all text elements
var texts []string
for _, item := range arr {
if item.Type == "text" && item.Text != "" {
texts = append(texts, item.Text)
}
}
c.Value = strings.Join(texts, "\n")
return nil
}
return fmt.Errorf("content field is neither string nor array format")
}
// MarshalJSON implements custom marshaling to always output as stringThis function is important because it defines how HumanLayer Tutorial: Context Engineering and Human-Governed Coding Agents implements the patterns covered in this chapter.
The MarshalJSON function in claudecode-go/types.go handles a key part of this chapter's functionality:
}
// MarshalJSON implements custom marshaling to always output as string
func (c ContentField) MarshalJSON() ([]byte, error) {
return json.Marshal(c.Value)
}
// Content can be text or tool use
type Content struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
Thinking string `json:"thinking,omitempty"`
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Input map[string]interface{} `json:"input,omitempty"`
ToolUseID string `json:"tool_use_id,omitempty"`
Content ContentField `json:"content,omitempty"`
}
// ServerToolUse tracks server-side tool usage
type ServerToolUse struct {
WebSearchRequests int `json:"web_search_requests,omitempty"`
}
// CacheCreation tracks cache creation metrics
type CacheCreation struct {
Ephemeral1HInputTokens int `json:"ephemeral_1h_input_tokens,omitempty"`
Ephemeral5MInputTokens int `json:"ephemeral_5m_input_tokens,omitempty"`
}
// Usage tracks token usage
type Usage struct {This function is important because it defines how HumanLayer Tutorial: Context Engineering and Human-Governed Coding Agents implements the patterns covered in this chapter.
flowchart TD
A[processStream]
B[displayToolCallWithResult]
C[UnmarshalJSON]
D[MarshalJSON]
E[UnmarshalJSON]
A --> B
B --> C
C --> D
D --> E