NetStacksNetStacks

AI Engineer Profile

How NetStacks composes the AI system prompt from personality segments and weighted vendor/domain knowledge packs per feature, the character budget, and where to configure it.

Overview

The AI Engineer Profile is the personality and expertise layer that NetStacks prepends to the system prompt for every AI feature. Instead of a single hard-coded prompt, NetStacks composes the prompt at request time from small, independent pieces: non-negotiable safety rules, an identity segment, an expertise segment, a behavior segment, and a set of knowledge packs chosen by your weighted vendor and domain preferences.

Composition is feature-aware. The three AI features — Chat, Agents, and ScriptGeneration — each request a different mix of segments and a different slice of the character budget, so the same profile produces a chatty, identity-rich prompt in AI Chat and a lean, expertise-only prompt for script generation.

Where this runs

The profile is owned by the Local Agent (the sidecar bundled with the Terminal) and stored in its local SQLite database. Prompt composition happens on-device before anything is sent to your configured LLM provider. Nothing about the profile is shared with NetStacks; see LLM Configuration for where the model itself lives.

How the Prompt Is Composed

Every AI request that uses a profile calls a single compile step: compile_for_feature(feature, max_context_chars). It returns the full system-prompt prefix as a string, which NetStacks then concatenates with live device and session context before sending it to the model. The compile step assembles a list of segments and joins them with blank lines.

Segment Layers

The profile compiles into up to four kinds of segments, always in this order:

Layer 0 — Safety Rules
A fixed block titled Safety Rules (Non-Negotiable). Always first, always present, never configurable. See Non-Negotiable Safety Rules.
Identity
Built from name, behavior_mode, and verbosity. Produces a line like "You are Atlas, a CCIE-level network engineer. You are a coworker — proactive, takes ownership, reports back when done." Omitted entirely if name is unset.
Expertise
Built from vendor_weights (rendered as percentages, sorted high to low),domain_focus (only domains weighted above 0.3 are named), cert_perspective, and environment_type. For example: "Primary expertise: Cisco (70%), Juniper (30%). Focus: routing, datacenter. Environment: production."
Behavior
Built from autonomy_level, troubleshooting_method, risk_tolerance, and any custom safety_rules you added.

After those segments, the compiler appends the selected knowledge packs. Each segment is individually optional (except safety): if the data that drives it is empty, that segment is skipped.

Here is roughly what a compiled Chat prompt prefix looks like:

## Safety Rules (Non-Negotiable)
1. Never guess device state — always run a show/display command before making assertions.
2. Never execute destructive commands (write erase, reload, format, ...) without explicit human approval.
... (8 rules total)

You are Atlas, a CCIE-level network engineer. You are a coworker — proactive, takes ownership, reports back when done.
Communication: balanced — concise but clear.

Primary expertise: Cisco (70%), Juniper (30%). Focus: routing, datacenter. Environment: production.

Autonomy: suggest fixes and wait for approval before acting.
Troubleshooting: top-down methodology.
Risk: conservative — always verify before changing.

## Core Networking Expertise
- OSI and TCP/IP model: map symptoms to layers ...
...

## Routing Protocol Expertise
### OSPF
...

## Cisco Platform Expertise
### IOS / IOS-XE
...

Per-Feature Assembly (Chat / Agents / ScriptGeneration)

The AiFeature attached to each request decides which segments are included and how much budget the knowledge packs get. There are exactly three features:

FeatureIdentityExpertiseBehaviorKnowledge packs
ChatYesYesYesFull pack budget
AgentsYesYesYesFull pack budget
ScriptGenerationNoYesNoLean — capped at 2000 chars

Chat (the AI Assistant side panel) and Agents (NOC Agents and their sub-agents) both get the full picture: identity, expertise, behavior, and as many knowledge packs as fit. ScriptGeneration (the "generate a Python script" path) drops the conversational identity and behavior segments entirely and loads only the expertise segment plus a deliberately small slice of packs, because a script generator needs platform facts, not bedside manner.

Which feature is calling?

You do not pick the feature — NetStacks sets it for you based on where the request originates. The AI Assistant uses Chat, NOC Agents and sub-agents use Agents, and the script generator uses ScriptGeneration. The same saved profile feeds all three.

Weighted Knowledge Packs

Knowledge packs are small, curated blocks of platform and protocol expertise compiled into the Agent. There are three categories:

  • Core — the Core Networking Expertise pack. Always loaded first and never optional. It covers the OSI/TCP-IP model, subnet math, interface-naming conventions, CLI navigation, show-command patterns, and log analysis.
  • Domain packs — selected by your domain_focus weights: routing, datacenter, security, wireless, and mpls.
  • Vendor packs — selected by your vendor_weights: cisco (IOS / IOS-XE / NX-OS), juniper (Junos), and arista (EOS).

Each domain and vendor you weight is a number from 0.0 to 1.0. The weight is not a percentage of the prompt — it is purely a priority for loading order. The loader sorts your domains by weight (highest first), then your vendors by weight (highest first), and walks the list, adding each matching pack only if it still fits the remaining character budget.

Loading algorithm

The order is: (1) always add the core pack and subtract its size; (2) add domain packs in weight order, each only if it fits; (3) add vendor packs in weight order, each only if it fits. A pack that does not fit is skipped — the loader keeps trying smaller packs further down the list, it does not stop at the first miss. So your highest-weighted areas are the ones most likely to survive a tight budget.

In the Settings UI, each pack is a toggle, not a slider: enabling a pack stores weight 1.0 and disabling it removes the key. The fine-grained fractional weights (like Cisco 70% / Juniper 30%) come from the conversational onboarding, which estimates them from your answers; you can still see them reflected in the compiled expertise line.

The Character Budget

Composition is bounded by a fixed character budget so the personality prefix never crowds out the actual conversation. The numbers below are the live defaults the Agent uses.

  • Total budget: 8000 characters (~2000 tokens) passed to the compile step for Chat, Agents, and ScriptGeneration.
  • Reserved buffer: 3000 characters are held back for the safety rules plus the identity/expertise/behavior segments.
  • Pack budget: the remaining 5000 characters are available for knowledge packs.
  • Core pack: always consumes its size first (roughly 0.6k chars), leaving about 4.4k for your optional domain and vendor packs.
  • ScriptGeneration override: the pack budget is additionally capped to 2000 characters, keeping script prompts lean.

The AI Engineer settings tab renders this as a live budget bar. It uses the same numbers the Agent does — it fetches pack sizes from /ai/knowledge-pack-sizes, which reports a total_budget of 5000 (that is, the 8000 total minus the 3000 reserve) and the available_budget after subtracting the core pack. As you toggle packs the bar fills; a pack that is enabled but would push you over budget is marked over budget and is not loaded.

# Inspect the exact pack sizes and budget the Agent uses
curl -s http://127.0.0.1:<agent-port>/api/ai/knowledge-pack-sizes | jq

# Example shape:
# {
#   "total_budget": 5000,
#   "core_size": 584,
#   "available_budget": 4416,
#   "packs": [
#     { "category": "core",   "name": "core",       "size": 584 },
#     { "category": "domain", "name": "routing",    "size": 1380 },
#     { "category": "domain", "name": "datacenter", "size": 1120 },
#     { "category": "vendor", "name": "cisco",      "size": 860 },
#     ...
#   ]
# }
Budget is per-request, not cumulative

The budget applies to a single composed prompt. It does not limit how many packs you may enable in Settings — you can enable more than fit. At request time the loader simply stops adding packs once the budget is full, dropping the lowest-priority ones. If you depend on a specific pack, give its domain or vendor a higher weight (or, in the UI, fewer competing packs) so it loads first.

Where to Configure It

There are two ways to build a profile, and they write to the same record.

1. Conversational onboarding

The first time you open the AI Assistant without a profile, NetStacks starts a short onboarding interview. It asks one question at a time — your AI's name, working style (assistant / coworker / mentor / silent), the gear you use, your domain, and how much autonomy to grant — then offers to go deeper on communication style, risk tolerance, troubleshooting method, certification perspective, experience level, environment, syntax style, and any always-off-limits commands. Your free-text answers are parsed into the structured profile fields (including fractional vendor/domain weights). When it emits its completion marker the profile is saved and onboarding will not run again until you reset.

2. The AI Engineer settings tab

Open Settings → AI Engineer to edit every field directly. The tab is grouped into Identity (AI name, working style, autonomy), Expertise (the knowledge-pack toggles with the budget bar, certification perspective, environment type), Behavior (verbosity, risk tolerance, troubleshooting method, experience level, syntax style, free-text communication style), and Custom Safety Rules. Each control saves on change. Editing here also marks onboarding complete, so opening Settings is itself a valid way to onboard.

Reset and re-onboard

The Reset Profile & Re-onboard button at the bottom of the tab clears all settings. The conversational onboarding then starts again the next time you open AI chat. This is the only thing that clears the "onboarding complete" flag — ordinary edits never silently revert it.

Direct API access

The Local Agent exposes the profile over its local HTTP API. This is handy for backups or scripted setup. The endpoints are:

  • GET /api/ai/profile — returns { profile } or null
  • PUT /api/ai/profile — create or update (send the full profile object)
  • DELETE /api/ai/profile — delete the profile and trigger re-onboarding
  • GET /api/ai/profile/status — reports whether onboarding is complete
  • GET /api/ai/knowledge-pack-sizes — pack sizes and budget for the bar
# Read the current profile
curl -s http://127.0.0.1:<agent-port>/api/ai/profile | jq '.profile'

# Write a profile (full object — fields not sent fall back to defaults)
curl -s -X PUT http://127.0.0.1:<agent-port>/api/ai/profile \
  -H 'Content-Type: application/json' \
  -d '{
    "id": 1,
    "name": "Atlas",
    "behavior_mode": "coworker",
    "autonomy_level": "suggest",
    "vendor_weights": { "cisco": 0.7, "juniper": 0.3 },
    "domain_focus": { "routing": 0.8, "datacenter": 0.5 },
    "cert_perspective": "ccie",
    "verbosity": "balanced",
    "risk_tolerance": "conservative",
    "troubleshooting_method": "top-down",
    "syntax_style": "full",
    "user_experience_level": "senior",
    "environment_type": "production",
    "safety_rules": ["Never touch core-router-1 without a change window"],
    "communication_style": "Be direct and technical, skip pleasantries",
    "onboarding_completed": true
  }'
Finding the Agent port

The Local Agent binds to a loopback port on the Terminal host. Use the value shown in the Terminal's diagnostics or your shell environment in place of <agent-port>. In normal use you never touch the API directly — the Settings tab is the supported path.

Profile Fields Reference

Every field, its accepted values, and its default. These are the exact values the compiler and the Settings UI understand.

FieldValuesDefaultDrives
namefree text(none)Identity. If unset, the whole identity segment is skipped.
behavior_modeassistant, coworker, mentor, silentassistantIdentity wording
autonomy_levelinform, suggest, actsuggestBehavior
vendor_weightsmap of cisco/juniper/arista → 0.0–1.0emptyExpertise line + vendor pack order
domain_focusmap of routing/datacenter/security/wireless/mpls → 0.0–1.0emptyExpertise (above 0.3) + domain pack order
cert_perspectivevendor-neutral, ccie, jncievendor-neutralExpertise ("Think like a CCIE")
verbosityterse, balanced, detailedbalancedIdentity communication line
risk_toleranceconservative, moderate, aggressiveconservativeBehavior
troubleshooting_methodtop-down, bottom-up, divide-and-conquertop-downBehavior
syntax_stylefull, shorthandfullStored preference
user_experience_leveljunior, mid, senior, expertmidCalibrates explanation depth
environment_typelab, production, msp, mixedproductionExpertise ("Environment: production")
safety_rulesarray of free-text rulesemptyBehavior (appended after built-in safety)
communication_stylefree text(none)Free-text personality notes
onboarding_completedbooleanfalseWhether onboarding runs on next chat
Why some domains do not appear in the prompt

The expertise line only names domains weighted above 0.3. A domain you weight at, say, 0.2 still influences pack-loading priority but will not be spelled out in the "Focus:" sentence. Vendors are always named (with their percentage) whenever vendor_weights is non-empty.

Worked Examples

Cisco-heavy routing engineer

Weight Cisco highest, add a touch of Juniper, focus on routing and a bit of data center. The compiled expertise line becomes "Primary expertise: Cisco (80%), Juniper (20%). Focus: routing. Environment: production." and packs load in the order core → routing → datacenter (if it fits) → cisco → juniper.

{
  "name": "Atlas",
  "behavior_mode": "coworker",
  "autonomy_level": "suggest",
  "vendor_weights":  { "cisco": 0.8, "juniper": 0.2 },
  "domain_focus":    { "routing": 0.9, "datacenter": 0.25 },
  "cert_perspective": "ccie",
  "environment_type": "production"
}

Note that datacenter at 0.25 is below the 0.3 threshold, so it is not named in the expertise sentence — but it still queues its pack after routing if budget remains.

Junos data-center fabric specialist

{
  "name": "Junie",
  "behavior_mode": "mentor",
  "autonomy_level": "inform",
  "verbosity": "detailed",
  "vendor_weights": { "juniper": 1.0, "arista": 0.6 },
  "domain_focus":   { "datacenter": 1.0, "mpls": 0.7, "routing": 0.5 },
  "cert_perspective": "jncie",
  "environment_type": "mixed"
}

With three domain packs and two vendor packs requested, the ~4.4k pack budget may not fit all five. They load by weight: datacenter, then mpls, then routing, then juniper, then arista — stopping whenever the next pack would overflow. Drop a domain or use fewer packs if you need a specific vendor pack guaranteed in.

Silent script-only setup

If you mainly use the script generator, remember it ignores identity and behavior and caps packs at 2000 chars. A lean profile that only sets expertise is enough:

{
  "behavior_mode": "silent",
  "vendor_weights": { "cisco": 1.0 },
  "domain_focus":   { "routing": 1.0 },
  "environment_type": "production"
}

For ScriptGeneration this compiles to the safety rules, the expertise line, the core pack, and the routing pack (truncated to the 2000-char cap) — no name, no working style, no behavior block.

Non-Negotiable Safety Rules

Before any profile segment, the compiler injects a fixed block of safety rules. These are hard-coded, cannot be configured or overridden, and are identical for Chat, Agents, and ScriptGeneration. No autonomy level bypasses them.

  1. Never guess device state — always run a show/display command before making assertions.
  2. Never execute destructive commands (write erase, reload, format, delete startup-config, request system zeroize) without explicit human approval.
  3. Never exfiltrate data — configs, credentials, topology, and network data stay local; nothing goes beyond the configured LLM provider.
  4. Always sanitize credentials — passwords, SNMP communities, API keys, routing secrets, VPN keys, and private keys are redacted before reaching any LLM provider.
  5. Never fabricate CLI output, interface names, IP addresses, or device states.
  6. Never bypass change management — follow MOPs and change requests regardless of autonomy level.
  7. Verify after every change and report failed verification immediately.
  8. Always identify as AI — never pretend to be a human operator in logs or recordings.
Custom safety rules add, never subtract

The custom rules you add in Settings → AI Engineer → Custom Safety Rules are appended to the behavior segment as additional constraints. They can only tighten behavior (e.g. "Never touch core-router-1 without a change window"). They cannot weaken or remove any of the eight built-in rules above.

Rule 4 is enforced separately by the credential sanitizer, which redacts secrets from anything bound for the model. See Source Code & Cryptography for how local-only handling is guaranteed.

Controller-Managed Profiles

In Personal Mode the profile lives entirely on your machine and you own every field. In a Controller-managed deployment, the AI Engineer profile becomes a shared, admin-curated resource.

Enterprise mode

When the Terminal is connected to a Controller, the AI Engineer settings tab switches from the full editor to a profile selector. Your organization's admin defines the available profiles centrally; you choose which one to activate for all AI features (or "None" to fall back to the default AI). The selector reads from the Controller's profile list and active-profile endpoints rather than the local Agent.

This lets a team standardize the AI's vendor focus, autonomy posture, and custom safety rules across everyone, while individuals still pick the profile that matches the task at hand. The composition mechanics — segments, packs, and the character budget — are identical; only the source and ownership of the profile change.

Q&A

Where do I edit my AI Engineer profile?
Settings → AI Engineer. The first time you open the AI Assistant without a profile you also get a conversational onboarding that builds one for you. Both write the same record.
What is the difference between Chat, Agents, and ScriptGeneration?
They are the three AI features that request a composed prompt. Chat and Agents both get the full identity + expertise + behavior + knowledge-pack mix. ScriptGeneration drops identity and behavior and uses a lean pack budget capped at 2000 chars. You do not choose the feature — it is set by where the request originates.
Do vendor/domain weights set how much prompt space a pack gets?
No. Weights only set loading priority. Packs are loaded whole, highest weight first, each only if it still fits the remaining character budget. A weight is not a percentage of the prompt.
Why is one of my enabled packs not in the prompt?
The character budget filled before the loader reached it. Total pack budget is ~5000 chars (8000 total minus a 3000 reserve), and the core pack always goes first. Raise the pack's weight, or enable fewer competing packs, so it loads earlier. The Settings budget bar flags over-budget packs.
Can I edit or remove the built-in safety rules?
No. The eight safety rules are hard-coded, always injected first, and apply to every feature and autonomy level. You can only add custom rules, which tighten behavior further.
What happens if I have no profile at all?
NetStacks falls back to the built-in safety rules plus a default system prompt, and the AI Assistant offers to run onboarding. You still get safe, capable behavior — just without your personalized identity, expertise weighting, and pack selection.
How do I start over?
Use Reset Profile & Re-onboard in the AI Engineer tab (or DELETE /api/ai/profile). This clears every field and re-runs onboarding the next time you open AI chat. It is the only action that clears the onboarding-complete flag.
Is any of this sent to NetStacks?
No. The profile is stored in the Local Agent's SQLite database and the prompt is composed on-device. Only the final composed prompt — with credentials sanitized — goes to your configured LLM provider.