Quiz 2

Actor-Critic Methods: A2C, A3C, and Advantage Estimation

3162 words
16 min read
Python Week 1: the first filter for runtime behavior
Visual companion
Python
Type and operator map

Python Week 1: the first filter for runtime behavior

View
Revision summary

What this note is really saying

Short form

# Actor-Critic Methods: A2C, A3C, and Advantage Estimation ## 🎯 Learning Objectives - Understand why combining policy gradients with value functions improves sample efficiency - Derive the advantage function and its role in reducing gradient variance - Implement Advantage Actor-Critic (A2C) - Understand A3C's async...

Actor-Critic Methods: A2C, A3C, and Advantage Estimation

🎯 Learning Objectives

  • Understand why combining policy gradients with value functions improves sample efficiency
  • Derive the advantage function and its role in reducing gradient variance
  • Implement Advantage Actor-Critic (A2C)
  • Understand A3C's asynchronous architecture
  • Analyze the bias-variance tradeoff in advantage estimation

📋 Prerequisites

  • Policy Gradients (Week 8): REINFORCE, score function, baseline
  • TD Learning (Week 5): Value function estimation, TD error
  • Deep Learning basics: Neural network optimization, sharing parameters

1. 📖 Core Content

1.1 Intuition: Why Combine Actor and Critic?

In REINFORCE (the basic policy gradient method), the agent uses the full Monte Carlo return GtG_t to evaluate its actions. This works but has high variance — you must complete many episodes before the signal averages out. In TD learning, the agent learns a value function that estimates expected returns with low variance (but some bias). Actor-Critic combines both:
  • Actor: The policy πθ(as)\pi_\theta(a|s) that decides which action to take
  • Critic: The value function Vϕ(s)V_\phi(s) or Qϕ(s,a)Q_\phi(s,a) that evaluates how good the state/action is The critic provides a low-variance baseline for the actor, reducing gradient variance. The actor improves the policy based on the critic's evaluation. This is the most widely used architecture in modern RL (PPO, SAC, TD3 are all actor-critic methods).

1.2 The Policy Gradient with a Critic

Recall the REINFORCE gradient:
θJ(θ)=Eπ[θlogπθ(as)Gt]\nabla_\theta J(\theta) = \mathbb{E}_\pi[\nabla_\theta \log \pi_\theta(a|s) \cdot G_t]
The Actor-Critic gradient replaces GtG_t with an advantage estimate:
θJ(θ)=Eπ[θlogπθ(as)A(s,a)]\nabla_\theta J(\theta) = \mathbb{E}_\pi[\nabla_\theta \log \pi_\theta(a|s) \cdot A(s, a)]
where A(s,a)=Q(s,a)V(s)A(s, a) = Q(s, a) - V(s) is the advantage function. The advantage tells us: "How much better is taking action aa compared to the average action in state ss?"

1.2.1 Why Advantage?

The value function V(s)V(s) acts as a baseline. Subtracting it from Q(s,a)Q(s,a) reduces variance without introducing bias:
Eaπ[θlogπ(as)b(s)]=0 for any baseline b(s)\mathbb{E}_{a \sim \pi}[\nabla_\theta \log \pi(a|s) \cdot b(s)] = 0 \text{ for any baseline } b(s)
Why? Because Eπ[θlogπ(as)]=θEπ[1]=θ1=0\mathbb{E}_\pi[\nabla_\theta \log \pi(a|s)] = \nabla_\theta \mathbb{E}_\pi[1] = \nabla_\theta 1 = 0. The baseline can be any function of ss (not aa). The optimal baseline is V(s)V(s), giving us the advantage A(s,a)=Q(s,a)V(s)A(s,a) = Q(s,a) - V(s).

1.3 Estimating the Advantage

We rarely have Q(s,a)Q(s,a) directly. Common advantage estimates (from simplest to most complex):

1.3.1 TD Error as Advantage

A(s,a)R+γV(s)V(s)TD error δA(s, a) \approx \underbrace{R + \gamma V(s') - V(s)}_{\text{TD error } \delta}
This is the simplest advantage estimate. The TD error tells us how much better/worse the actual outcome was compared to the expected value. Bias vs Variance: This has low variance (one-step TD) but can be biased if VV is inaccurate.

1.3.2 Monte Carlo Advantage

A(s,a)GtV(s)A(s, a) \approx G_t - V(s)
Low bias (uses complete return) but very high variance.

1.3.3 Generalized Advantage Estimation (GAE)

GAE (Schulman et al., 2016) smoothly interpolates between TD and MC advantages:
AtGAE(γ,λ)=l=0(γλ)lδt+lA^{GAE(\gamma, \lambda)}_t = \sum_{l=0}^\infty (\gamma\lambda)^l \delta_{t+l}
where δt=Rt+1+γV(St+1)V(St)\delta_t = R_{t+1} + \gamma V(S_{t+1}) - V(S_t). This is exactly TD(λ) applied to advantage estimation:
  • λ=0\lambda = 0: 1-step TD advantage (high bias, low variance)
  • λ=1\lambda = 1: Monte Carlo advantage (low bias, high variance)
  • λ=0.95\lambda = 0.95: typical in practice (balanced tradeoff)

1.4 A2C: Advantage Actor-Critic

A2C uses synchronous training with multiple parallel environments. (Diagram)

1.4.1 A2C Loss Functions

Actor loss (policy gradient):
Lactor=1Ni=1Ntlogπθ(at(i)st(i))At(i)\mathcal{L}_{actor} = -\frac{1}{N} \sum_{i=1}^N \sum_{t} \log \pi_\theta(a_t^{(i)}|s_t^{(i)}) \cdot A_t^{(i)}
Critic loss (value function regression):
Lcritic=1Ni=1Nt(Gt(i)Vϕ(st(i)))2\mathcal{L}_{critic} = \frac{1}{N} \sum_{i=1}^N \sum_{t} (G_t^{(i)} - V_\phi(s_t^{(i)}))^2
Entropy bonus (encourages exploration):
Lentropy=1Ni=1Ntaπθ(ast(i))logπθ(ast(i))\mathcal{L}_{entropy} = -\frac{1}{N} \sum_{i=1}^N \sum_{t} \sum_a \pi_\theta(a|s_t^{(i)}) \log \pi_\theta(a|s_t^{(i)})
Total loss:
L=Lactor+c1Lcriticc2Lentropy\mathcal{L} = \mathcal{L}_{actor} + c_1 \mathcal{L}_{critic} - c_2 \mathcal{L}_{entropy}

1.4.2 A2C Algorithm

text
Initialize actor π_θ and critic V_φ networks
loop for T steps:
    for each worker i in parallel:
        Run policy πθ for n steps
        Store (s_t, a_t, r_t, s_{t+1}) in trajectory buffer
    Compute advantages using GAE
    for each worker i:
        Compute actor loss, critic loss, entropy bonus
    Gradient step on combined loss
    Update θ, φ

Worked Example 1: A2C Advantage Computation

A3 steps for a single worker:
  • Step 1: s₁ → a₁ → r₁=1, s₂
  • Step 2: s₂ → a₂ → r₂=0, s₃
  • Step 3: s₃ → a₃ → r₃=2, s₄ (terminal) Current critic values: V(s₁)=0.5, V(s₂)=0.3, V(s₃)=0.1, V(s₄)=0. γ=0.9. Compute TD errors: δ₁ = 1 + 0.9(0.3) - 0.5 = 1 + 0.27 - 0.5 = 0.77 δ₂ = 0 + 0.9(0.1) - 0.3 = 0 + 0.09 - 0.3 = -0.21 δ₃ = 2 + 0.9(0) - 0.1 = 1.9 Compute GAE(γ=0.9, λ=0.95): A₁ = δ₁ + 0.9(0.95)(-0.21) + (0.9·0.95)²(1.9) = 0.77 + 0.855(-0.21) + 0.731(1.9) = 0.77 - 0.180 + 1.389 = 1.979 A₂ = δ₂ + 0.9(0.95)(1.9) = -0.21 + 1.625 = 1.415 A₃ = δ₃ = 1.9 The advantages are highest for a₁ and a₃ because they led to high rewards. a₂ had negative TD error (the actual reward was worse than expected), but the GAE positive future advantage compensates.

1.5 A3C: Asynchronous Advantage Actor-Critic

A3C extends A2C with asynchronous training: multiple workers independently interact with their environments and update a shared global network asynchronously. (Diagram)

Key Differences from A2C

AspectA2C (Synchronous)A3C (Asynchronous)
WorkersAll workers sync before updateWorkers update independently
GradientSum over all workersEach worker sends gradients when ready
StabilityMore stable gradientsMore diverse exploration
Wall-clock speedSlower (sync wait)Faster (no waiting)
Hardware utilizationLess efficientMore efficient

1.6 A2C vs A3C vs DQN vs PPO

MethodActor-Critic?ParallelismKey Innovation
REINFORCENo (no critic)NoneBasic policy gradient
A2CYesSyncSynchronous multi-worker
A3CYesAsyncAsynchronous multi-worker
DQNNo (value-only)Replay bufferExperience replay + target net
PPOYesSyncClipped surrogate objective

1.7 Edge Cases & Gotchas

  • Shared vs separate networks: Actor and critic can share early layers (common in A2C/A3C). This speeds learning but may cause interference — fix by orthogonal initialization.
  • GAE λ sensitivity: The choice of λ significantly affects performance. Too low λ (0-0.9): high bias, potentially too conservative. Too high λ (0.99-1): high variance, unstable learning.
  • Entropy coefficient: If entropy bonus is too large, the policy never converges (stays random). If too small, it converges prematurely to a suboptimal policy.
  • Value function as baseline only: The advantage should center at ~0. If advantages are consistently positive, the value function is underestimating; if consistently negative, it's overestimating.
  • n-step returns: Instead of GAE, using n-step returns for advantage (k=0n1γkrt+k+γnV(st+n)V(st)\sum_{k=0}^{n-1} \gamma^k r_{t+k} + \gamma^n V(s_{t+n}) - V(s_t)) is simpler and works well.

1.8 Why This Matters

Actor-Critic methods are the foundation of almost all modern deep RL:
AlgorithmRelationship to Actor-Critic
PPOActor-Critic + clipped surrogate
SACActor-Critic + entropy regularization + double Q
TD3Actor-Critic + double Q + target policy smoothing
IMPALAA3C-style async with V-trace off-policy correction
AlphaZeroMCTS as actor, neural network as critic
If you understand A2C, you can understand all of these — they add specific modifications on top of the same core idea.

2. 📐 Key Formulas / Concepts

ConceptFormulaDescription
Actor gradient$\nabla_\theta J = \mathbb{E}[\nabla_\theta \log \pi_\theta(as) \cdot A(s,a)]$
AdvantageA(s,a)=Q(s,a)V(s)A(s,a) = Q(s,a) - V(s)Action quality relative to baseline
TD advantageAR+γV(s)V(s)A \approx R + \gamma V(s') - V(s)1-step advantage estimate
GAEAtGAE=l=0(γλ)lδt+lA^{GAE}_t = \sum_{l=0}^\infty (\gamma\lambda)^l \delta_{t+l}λ-weighted advantage estimate
A2C lossL=Lactor+c1Lcriticc2Lentropy\mathcal{L} = \mathcal{L}_{actor} + c_1 \mathcal{L}_{critic} - c_2 \mathcal{L}_{entropy}Combined objective
Value function baselineE[logπb(s)]=0\mathbb{E}[\nabla \log \pi \cdot b(s)] = 0Baseline doesn't bias gradient

3. ⚠️ Common Pitfalls

Pitfall 1: Not Normalizing Advantages

Mistake: Using raw advantages without normalization. Why: If advantages are all very large (e.g., range [-100, 100]), the policy gradient update can be huge, destabilizing training. Correct approach: Normalize advantages across the batch (subtract mean, divide by standard deviation). This centers the advantages around 0 with unit variance, providing a stable gradient scale.

Pitfall 2: Sharing Too Many Parameters Between Actor and Critic

Mistake: Using a fully shared network for policy and value. Why: The actor and critic have different objectives. The actor wants to maximize returns; the critic wants to predict returns accurately. Sharing all parameters forces one network to serve two masters, which can lead to feature interference. Correct approach: Share early layers (feature extractors) but use separate output heads for policy and value. This balances sharing (efficient representation learning) with separation (avoiding interference).

Pitfall 3: Setting Entropy Coefficient Too High or Too Low

Mistake: Using a fixed entropy coefficient without tuning. Why: Early training benefits from high entropy (exploration). Late training should have low entropy (exploitation). A fixed coefficient that's good for early training may prevent convergence; one good for late training may never explore enough. Correct approach: Start with a moderate entropy coefficient (e.g., 0.01) and anneal it. Or use adaptive entropy tuning (SAC style).

Pitfall 4: Incorrect GAE Computation at Episode Boundaries

Mistake: Computing GAE across episode boundaries. Why: The TD error formula assumes the value of the terminal state is 0. If the trajectory buffer includes states from two different episodes, the bootstrap value at the episode boundary is wrong. Correct approach: Reset the GAE computation at episode boundaries. When s_{t+1} is terminal, set V(s_{t+1}) = 0 and don't continue the GAE sum beyond that point.

4. 📝 Practice Questions

Q1: Derive why any state-dependent baseline b(s) doesn't bias the policy gradient.
The policy gradient with baseline:
θJ=Esdπ,aπ[θlogπθ(as)(Qπ(s,a)b(s))]\nabla_\theta J = \mathbb{E}_{s \sim d^\pi, a \sim \pi}[\nabla_\theta \log \pi_\theta(a|s) \cdot (Q^\pi(s,a) - b(s))]
The bias introduced by b(s) is:
Bias=Es,a[θlogπθ(as)b(s)]\text{Bias} = \mathbb{E}_{s,a}[\nabla_\theta \log \pi_\theta(a|s) \cdot b(s)]
=Esdπ[b(s)Eaπ[θlogπθ(as)]]= \mathbb{E}_{s \sim d^\pi}[b(s) \cdot \mathbb{E}_{a \sim \pi}[\nabla_\theta \log \pi_\theta(a|s)]]
Now, Eaπ[θlogπθ(as)]=aπθ(as)θlogπθ(as)\mathbb{E}_{a \sim \pi}[\nabla_\theta \log \pi_\theta(a|s)] = \sum_a \pi_\theta(a|s) \nabla_\theta \log \pi_\theta(a|s)
=aθπθ(as)=θaπθ(as)=θ1=0= \sum_a \nabla_\theta \pi_\theta(a|s) = \nabla_\theta \sum_a \pi_\theta(a|s) = \nabla_\theta 1 = 0
Therefore, the bias term = 0 for any b(s) that doesn't depend on a. The optimal baseline that minimizes variance is b(s)=Vπ(s)b(s) = V^\pi(s), making A(s,a)=Qπ(s,a)Vπ(s)A(s,a) = Q^\pi(s,a) - V^\pi(s) the advantage function. Q2: For GAE with λ=0, show that AtGAE=δtA_t^{GAE} = \delta_t (TD error). For λ=1, show that AtGAE=GtV(st)A_t^{GAE} = G_t - V(s_t) (MC advantage).
λ=0: AtGAE=l=0(γ0)lδt+l=δt+0+0+...=δtA_t^{GAE} = \sum_{l=0}^\infty (\gamma \cdot 0)^l \delta_{t+l} = \delta_t + 0 + 0 + ... = \delta_t
This is exactly the 1-step TD error, giving highest bias/lowest variance.
λ=1: AtGAE=l=0(γ1)lδt+l=δt+γδt+1+γ2δt+2+...A_t^{GAE} = \sum_{l=0}^\infty (\gamma \cdot 1)^l \delta_{t+l} = \delta_t + \gamma \delta_{t+1} + \gamma^2 \delta_{t+2} + ...
Expanding: δt=rt+γV(st+1)V(st)\delta_t = r_t + \gamma V(s_{t+1}) - V(s_t) γδt+1=γ(rt+1+γV(st+2)V(st+1))\gamma \delta_{t+1} = \gamma(r_{t+1} + \gamma V(s_{t+2}) - V(s_{t+1})) γ2δt+2=γ2(rt+2+γV(st+3)V(st+2))\gamma^2 \delta_{t+2} = \gamma^2(r_{t+2} + \gamma V(s_{t+3}) - V(s_{t+2}))
Summing (telescoping): = rt+γrt+1+γ2rt+2+...V(st)=GtV(st)r_t + \gamma r_{t+1} + \gamma^2 r_{t+2} + ... - V(s_t) = G_t - V(s_t)
This is the MC advantage, giving lowest bias/highest variance. Q3: In A2C with 8 parallel workers, each collecting n=5 steps per update, what's the effective batch size? How does this compare to a single-worker A2C with n=40 steps?
With 8 workers × 5 steps = 40 (s, a, r) transitions per update. With 1 worker × 40 steps = 40 transitions per update.
The batch size in terms of transitions is the same (40).
However, the multi-worker approach has two advantages:
  1. Diverse exploration: Each worker experiences different states, reducing correlation between samples. This is like having a more diverse replay buffer.
  2. Wall-clock efficiency: With 8 workers, collecting 5 steps each takes ~5 step-times. Single worker needs 40 step-times (the environment step is often the bottleneck).
Multi-worker A2C gives better gradient estimates (lower variance) because the batch contains more diverse, less correlated samples. Q4: The entropy bonus in A2C is -c₂·H(π). Will this increase or decrease exploration? What happens if c₂ is too large?
The entropy H(π)=aπ(as)logπ(as)H(\pi) = -\sum_a \pi(a|s) \log \pi(a|s) is maximized when the policy is uniform (max entropy) and minimized when it's deterministic (zero entropy).
The loss includes -c₂·H(π), meaning we're subtracting entropy. Since we minimize the total loss, this encourages higher entropy (exploration).
If c₂ is too large:
  • The policy remains near-uniform (never specializes)
  • The agent never learns to exploit good actions
  • The policy gradient signal is overwhelmed by the entropy bonus
  • The agent effectively acts randomly
If c₂ is too small:
  • The policy converges quickly to a deterministic policy
  • The agent may converge to a suboptimal deterministic policy without exploring enough
Typical values: c₂ = 0.01 to 0.1 for continuous control, c₂ = 0.001 to 0.01 for Atari. Q5: Explain why A3C's asynchronous updates can lead to "gradient staleness" and how it's mitigated.
Gradient staleness: Worker A reads global parameters at time t, computes gradients for 5 steps, and sends updates at time t+5. Meanwhile, Workers B, C, D also computed and applied their gradients. Worker A's gradients were computed using stale parameters (from t) and are being applied to potentially very different parameters (at t+5).
This is like using a map from last week to navigate today — the terrain may have changed.
Mitigations:
  1. n-step returns limit staleness: Each worker only collects n steps (e.g., 5-20) before updating, limiting the staleness window.
  2. RMSProp/Adam with global learning rate: Adaptive optimizers are more robust to stale gradients.
  3. Trust region methods (PPO): By clipping the surrogate objective, PPO limits how much each update can change the policy, making it more robust to stale gradients.
  4. IMPALA's V-trace: Corrects for the off-policyness introduced by stale parameters using importance sampling.
  5. Synchronous A2C avoids staleness entirely: all workers sync before each update, ensuring gradients are computed on the same parameters being updated.
Q6: An A2C agent's advantages are all positive (range [0.5, 2.0]) for an entire training run. What does this indicate?
Consistently positive advantages mean that the critic (value function) is underestimating the value of every state. For every state visited, the actual return is better than predicted.
This indicates a systematic bias in the critic:
  1. The critic is too pessimistic: It consistently underestimates V(s)
  2. The actor is outperforming expectations: The actual returns are better than what the critic expects
Consequences:
  • The policy gradient update is always positive (increase log probability of all actions)
  • Relative differences between actions are preserved (since advantages scale differently per state-action)
  • The learning signal is weaker than it should be (advantages should be centered around 0)
Fix: Normalize advantages to have zero mean across the batch. This is standard practice in A2C implementations. Q7: Compare A2C with a batch size of 32 (single worker, 32 steps per update) vs A2C with batch size 32 (4 workers, 8 steps each).
AspectSingle Worker (32 steps)4 Workers (8 steps each)
Data correlationHigh (temporally adjacent states are similar)Low (different env states)
Exploration diversityLow (one trajectory)High (4 trajectories)
Wall-clock per update32 environment steps8 environment steps + sync
Gradient varianceHigher (correlated data)Lower (diverse data)
Experience diversitySingle sequence of 324 different sequences
The multi-worker version generally gives better gradients (lower variance) and faster wall-clock training. This is why A2C/A3C are preferred over single-worker variants. Q8: Derive the actor loss gradient for a single (s,a) transition with advantage A.
The actor loss for a single transition is:
Lactor(s,a)=logπθ(as)A\mathcal{L}_{actor}(s,a) = -\log \pi_\theta(a|s) \cdot A
The gradient is:
θLactor=θlogπθ(as)A\nabla_\theta \mathcal{L}_{actor} = -\nabla_\theta \log \pi_\theta(a|s) \cdot A
For a Gaussian policy (continuous action space): πθ(as)=N(μθ(s),σθ2(s))\pi_\theta(a|s) = \mathcal{N}(\mu_\theta(s), \sigma_\theta^2(s))
logπθ(as)=(aμθ(s))22σθ2(s)log(2πσθ(s))\log \pi_\theta(a|s) = -\frac{(a-\mu_\theta(s))^2}{2\sigma_\theta^2(s)} - \log(\sqrt{2\pi}\sigma_\theta(s))
θlogπθ=aμθ(s)σθ2(s)θμθ(s)(aμθ(s))2σθ2(s)σθ3(s)θσθ(s)\nabla_\theta \log \pi_\theta = \frac{a - \mu_\theta(s)}{\sigma_\theta^2(s)} \cdot \nabla_\theta \mu_\theta(s) - \frac{(a - \mu_\theta(s))^2 - \sigma_\theta^2(s)}{\sigma_\theta^3(s)} \cdot \nabla_\theta \sigma_\theta(s)
For a categorical policy (discrete actions): πθ(as)=softmax(hθ(s))a\pi_\theta(a|s) = \text{softmax}(h_\theta(s))_a
θlogπθ(as)=θhθ(as)aπθ(as)θhθ(as)\nabla_\theta \log \pi_\theta(a|s) = \nabla_\theta h_\theta(a|s) - \sum_{a'} \pi_\theta(a'|s) \nabla_\theta h_\theta(a'|s)
where hθ(as)h_\theta(a|s) is the logit for action a.
The advantage A scales the gradient — actions with positive advantage are made more likely; actions with negative advantage are made less likely. Q9: In A2C, the critic loss Lcritic=(GtVϕ(st))2\mathcal{L}_{critic} = (G_t - V_\phi(s_t))^2 is the MSE between the return and the predicted value. Why use MSE rather than absolute error?
MSE has a squared penalty (quadratic in error), while MAE has a linear penalty. For value estimation:
  1. Gradient magnitude: MSE gradient is proportional to the error (GtVϕ(st))(G_t - V_\phi(s_t)), so large errors produce larger updates. This helps the critic quickly correct large mistakes.
  2. Sensitivity to outliers: MSE is more sensitive to outliers (returns far from the predicted value). This is actually desirable in RL because rare, high-return episodes are informative — we want the critic to learn from them quickly.
  3. Convergence properties: MSE corresponds to the variance-minimizing estimator (assuming Gaussian noise). The critic aims to estimate E[GtSt=s]\mathbb{E}[G_t|S_t=s], and under MSE, the minimizer is the conditional expectation.
  4. Smoothness: MSE has smooth gradients everywhere, making optimization easier.
The downside of MSE is that for very large errors (e.g., initial training), gradients can be too large, causing training instability. This is one reason advantage normalization is used — it keeps the critic targets and predictions in a reasonable range. Q10: Explain the "deadly triad" in actor-critic methods with function approximation.
The "deadly triad" refers to the combination of three elements that can cause instability and divergence in RL:
  1. Function approximation: Representing V(s) or π(a|s) with a neural network (not a table)
  2. Bootstrapping: Updating based on current estimates (TD learning)
  3. Off-policy learning: Learning about one policy from data generated by another
Actor-critic methods with off-policy data (e.g., using a replay buffer) combine all three:
  1. Neural network parameterization (function approximation)
  2. TD error for the critic update (bootstrapping)
  3. Behavior policy differs from target policy when using stale data (off-policy)
Manifestations:
  • Value function may diverge (grow without bound)
  • Policy may oscillate between very different behaviors
  • Learning may get stuck in poor local optima
Mitigations:
  • A2C avoids off-policy learning: On-policy updates using fresh data from current policy
  • PPO: Constrains policy changes to a trust region
  • Target networks: Stabilize bootstrapping targets (used in DQN, SAC, TD3)
  • Gradient clipping: Prevents huge updates from rare large errors
On-policy actor-critic (A2C, PPO) avoids the off-policy part of the triad, which is a key reason for their stability.

5. 🔗 Cross-References

Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.