Durable objective
The objective is the durable statement of what the session is trying to achieve. It survives turns, compaction, and resume, and it is separate from a goal: a goal is one attempt to advance the objective.
The objective feature and agent-driven mode changes are on by default. Turn them off with NEXGEN_EXPERIMENTAL_OBJECTIVE=0 and NEXGEN_EXPERIMENTAL_AGENT_MODES=0. The ModeControl tool, which lets the agent enter plan or swarm mode, also needs [modes] agent_control = true, which is the default.
What the objective is
An objective is one short piece of text with a monotonic revision number and its source (user or model). It has no terminal state: it is set, replaced, or cleared. Every change is written to the session wire, so it is reconstructed on resume.
When the objective changes, NexgenK publishes an objective.updated event on the session stream. That event is separate from goal.updated, so updating the objective never clears a goal or promotes a queued goal.
Enable the objective
Both flags are on by default. Set them to 0 to return to the previous behavior:
NEXGEN_EXPERIMENTAL_OBJECTIVE=0 NEXGEN_EXPERIMENTAL_AGENT_MODES=0 nexgenkWith NEXGEN_EXPERIMENTAL_OBJECTIVE=0, the interface behaves as before: no objective is captured, no box appears, and the SetObjective and AskSuperUserQuestion tools are not registered. With [modes] agent_control = false, the agent cannot change modes by itself, and with [swarm] allow_agent_entry = false it cannot turn swarm mode on for a turn.
Capture objective blocks
A block wrapped in the configured marker is captured from the conversation:
<objetivo>
Redactar el informe trimestral y validarlo con finanzas.
</objetivo>A block written by the user is applied immediately. A block written by the model becomes a proposal that you apply yourself, so the model cannot silently narrow the objective. The last block in a message wins. Inline mentions, code fences whose language is not text, and blocks larger than max_chars are ignored or rejected with a visible reason.
Configure the objective
All settings live in the [objective] section of config.toml:
[objective]
markers = ["<objetivo>"]
max_chars = 2000
inject = "change"
max_goal_rewrites = 3
scan_max_chars = 32000
box = "auto"
superuser_timeout_ms = 120000| Key | Default | Effect |
|---|---|---|
markers | ["<objetivo>"] | Text markers that delimit an objective block |
max_chars | 2000 | Largest accepted objective; longer text is rejected, never truncated |
inject | "change" | When to remind the agent: on each revision change, every turn ("turn"), or never ("off") |
max_goal_rewrites | 3 | How many goals may be rewritten for the same objective revision |
scan_max_chars | 32000 | Messages larger than this are not scanned for blocks |
box | "auto" | Objective box visibility: "auto", "on", or "off" |
superuser_timeout_ms | 120000 | Timeout for the AskSuperUserQuestion consultation |
The objective box
When the objective is visible, the terminal UI shows a compact box above the editor. The collapsed line shows the revision and the start of the text, followed by ctrl+r. Press ctrl+r to expand or collapse it. The expanded box wraps the full text, keeps at most eight rows, and scrolls inside that body. The box is centered and never wider than 76 columns.
With box = "off" the box is hidden. With box = "auto" it appears when an objective exists; it collapses on very short terminals so an approval prompt and the editor still fit.
Objective, goals, and rewrites
The objective rules, and goals serve it:
- A goal created for an objective records which revision it came from (
derivedFromandderivedFromRevision). - When the goal is
blockedand the objective still stands, the agent rewrites the goal smaller instead of giving up. - The rewrite budget is
max_goal_rewrites(3 by default). When it is exhausted, the agent stops rewriting and reports the blocker to you. - A new objective revision resets the rewrite budget.
- The objective never completes on its own. Clear it or replace it when the work changes.
Recovery from failed turns
The main agent has no per-turn step cap, so a goal turn ends only when the agent stops working or the goal changes. If a turn fails for a reason that can change, the goal stays active and NexgenK schedules the next continuation automatically: 2 seconds later, then 10 seconds, 1 minute, 5 minutes, and every 30 minutes after that. A successful turn resets the sequence.
The recovery prompt tells the agent which error broke the previous turn and asks it to diagnose the failure instead of repeating the same action. After five consecutive recoveries the agent receives a reminder to change its approach or report the blocker instead of retrying forever.
Retrying cannot fix some failures, so those pause the goal instead: an invalid API key or permission error, a missing or invalid model configuration, a turn you cancelled, and a turn blocked by a UserPromptSubmit hook. In each case the pause reason in goal.updated names the cause, and /goal resume continues the work once you fix it.
Headless commands
In print mode, NexgenK interprets two commands without sending them to the model:
| Command | Effect |
|---|---|
/objective set <text> | Applies the text as the current objective |
/objective apply | Applies the pending model proposal |
In text output, the revision is reported once on stderr as Objective (revision N): .... In --output-format stream-json, each line is a JSON object; an objective change is a {"role":"meta","type":"objective.updated",...} line written after any open thinking block closes.
REST and SDK
The server exposes the durable objective on the session:
| Method | Path | Purpose |
|---|---|---|
GET | /api/v1/sessions/{session_id}/objective | Read the record, including a pending proposal |
PUT | /api/v1/sessions/{session_id}/objective | Set the objective from { "text": "..." } |
DELETE | /api/v1/sessions/{session_id}/objective | Clear the objective |
POST | /api/v1/sessions/{session_id}/objective/apply | Apply the pending proposal |
The SDK exposes the same operations as session.getObjective(), session.setObjective(), session.clearObjective(), and session.applyObjective(). ResumedAgentState.objective carries the durable record even when the session has no goal.