Cyphon

Backend

Location: app/server/modules/monitor/

This document explains how the backend processes Cyphon requests.


Backend Architecture

API Request
    │
    ▼
Export File (discovery.export.ts / intel.export.ts)
    │
    ▼
Service Class (Discovery.ts / Search.ts)
    │
    ▼
AI Processing / Data Sources
    │
    ▼
Response

Part 1: Command Classification (Discovery.ts)

File: app/server/modules/monitor/src/intel/Discovery.ts

When a user types a question, we need to figure out which commands to run.

The executeCyphonQuery Method


async executeCyphonQuery(question: string) {
  // 1. Validate input
  if (!question || question.trim().length === 0) {
    throw new Error("Empty Query");
  }

  // 2. Build the AI prompt
  const prompt = CYPHON_PROMPTS.COMMANDS_CLASSIFICATION.prompt
    .replace("{COMMANDS_JSON}", JSON.stringify(cyphonCommands, null, 2))
    .replace("{USER_QUERY}", question.trim());

  // 3. Send to AI and get response
  return genericAI.executePromptRaw(prompt);
}

What Happens Inside

  1. Input: User question like "scan google.com for whois"
  2. Prompt Building: Combines the question with available commands
  3. AI Processing: AI analyzes and picks relevant commands
  4. Output: JSON with matched commands

Part 2: AI Prompts (cyphon.ts)

File: app/server/modules/monitor/src/ai/prompts/cyphon.ts

This file contains the prompts that tell the AI what to do.

COMMANDS_CLASSIFICATION Prompt


export const CYPHON_PROMPTS = {
	COMMANDS_CLASSIFICATION: {
		prompt: `
    You are an intelligent command-discovery assistant.

    Your task is to analyze a user query and identify ALL commands 
    from the available command list that are relevant to the user's intent.

    AVAILABLE COMMANDS:
    {COMMANDS_JSON}

    USER QUERY:
    {USER_QUERY}

    INSTRUCTIONS:
    1. Understand the user's intent.
    2. Find all commands that match the intent.
    3. Extract required parameters from the user query.
    4. Generate a formatted command call.

    RESPONSE FORMAT (Return ONLY valid JSON):
    {
      "relevantCommands": [
        {
          "id": "command_id",
          "formattedOutput": "commandName(extracted_value)"
        }
      ]
    }
    `,
	},
};

RESULTS_SUMMARY Prompt


RESULTS_SUMMARY: {
	prompt: `
  You are a professional security consultant explaining 
  technical findings to a non-technical user.

  The user searched for: "{USER_QUERY}"

  Here are the security scan results:
  {RESULTS_JSON}

  YOUR TASK:
  Write a brief, professional overview (2-4 sentences) that:
  1. Summarizes what was found in plain English
  2. Highlights any important details
  3. Mentions if anything looks concerning
  4. Uses simple language

  RESPONSE FORMAT (Return ONLY valid JSON):
  {
    "summary": "Your professional summary here...",
    "highlights": ["key point 1", "key point 2"]
  }
  `;
}

Part 3: Available Commands (cyphonCommands.ts)

File: app/server/modules/monitor/src/views/cyphonCommands.ts

This defines all commands that Cyphon can execute.

Command Structure


export interface CyphonCommand {
	name: string; // "whois"
	description: string; // "Retrieves WHOIS information..."
	syntax: string; // "whois(domain)"
	parameters: Array<{
		name: string; // "domain"
		type: string; // "string"
		required: boolean; // true
		description: string; // "Domain name to query"
		example?: string; // "example.com"
	}>;
	keywords: string[]; // ["whois", "domain", "registration"]
	example: string; // 'whois("example.com")'
	category: string; // "Domain Intelligence"
	icon: string; // "mdi:domain"
}

Example Command

{
  name: "whois",
  description: "Retrieves WHOIS information for the provided domain.",
  syntax: "whois(domain)",
  parameters: [
    {
      name: "domain",
      type: "string",
      required: true,
      description: "Domain name to query WHOIS information for",
      example: "example.com"
    }
  ],
  keywords: ["whois", "domain", "registration", "owner", "registrar"],
  example: 'whois("example.com")',
  category: "Domain Intelligence",
  icon: "mdi:domain"
}

Part 4: Search Execution (Search.ts)

File: app/server/modules/ai/src/Search.ts

Once we have commands, they need to be executed. The Search class orchestrates this.

How Search Works


class Search {
	private sources: BaseSearch<any>[]; // Array of search sources
	private mqqueue: MQQueue; // Message queue for jobs

	// Start a search job
	async runSearch(searchRequest) {
		// 1. Parse the search query
		searchRequest.parsed = this.parser.parse(searchRequest.query);

		// 2. Create a unique job ID
		const reqId = `search-${uuidv4()}`;

		// 3. Add to queue and return job ID
		const job = await this.searchQueue.add(reqId, searchRequest);
		return job.id;
	}

	// Get results for a job
	async getJobData(jobId) {
		const job = await this.searchQueue.getJob(jobId);
		const jobState = await job.getState();

		return {
			id: jobId,
			results: job.data.results,
			progress: job.progress,
			done: jobState === "completed",
		};
	}
}

The Job Queue Pattern

User Request → Create Job → Add to Queue → Process Async → Poll for Results

This allows searches to run in the background while the user waits.


Part 5: Search Sources

File: app/server/modules/monitor/intel.export.ts

Multiple sources are combined to provide comprehensive results:


const sources = [
	new AssetsSearch(), // Internal asset database
	new DetectionSearch(), // Threat detections
	new IntelSearch(), // Intelligence feeds
	new RyzenSearch(), // Ryzen data source
	new SintelSearch(), // Security intel
	new LLMSearch(), // AI-powered search
	new RemediationSearch(), // Remediation suggestions
	new IncidentDetectionIntel(), // Incident data
	new DomainSpoofingSearch(), // Domain spoof checks
	new ThreatAIOverview(), // AI threat analysis
	new DiscoverSearch(), // Discovery scans
	new PlatformSearch(), // Platform data
];

How Sources Work

Each source implements a common interface:


interface BaseSearch {
	getCapabilities(): object; // What this source can search
	search(query): Promise<Results>; // Execute the search
}

Part 6: Export Files (API Routes)

discovery.export.ts

// Routes API calls to Discovery service

async executeCyphonQuery(message: Message) {
  return discovery.executeCyphonQuery(message.body.question);
}

async summarizeCyphonResults(message: Message) {
  return discovery.summarizeCyphonResults(
    message.body.userQuery,
    message.body.results
  );
}

intel.export.ts


async search(message: Message) {
  // Check feature flag
  if (!FeatureFlag.isEnabled("intel_cyphon", message.cx))
    throw new Error("Feature disabled.");

  let jobId = message.body.id;

  // If no job ID, start new search
  if (!jobId && message.body.keyword) {
    jobId = await searchManager.runSearch({
      org: await message.owner.getCurrentWorkspace(),
      owner: message.owner,
      query: message.body.keyword,
    });
  }

  // Return job results
  if (jobId) {
    return await searchManager.getJobData(jobId);
  }
}

Data Flow Summary

Step 1: User Query → Commands

"scan google.com"
    │
    ▼ executeCyphonQuery()
    │
    ▼ AI + COMMANDS_CLASSIFICATION prompt
    │
    ▼
{ relevantCommands: [{ formattedOutput: "whois(\"google.com\")" }] }

Step 2: Commands → Results

"whois(\"google.com\")"
    │
    ▼ intelAPI.search()
    │
    ▼ Search.runSearch() → Job Queue
    │
    ▼ Multiple Sources Execute
    │
    ▼
{ results: [{ cardType: "Whois", facts: {...} }] }

Step 3: Results → Summary

[{ cardType: "Whois", facts: {...} }]
    │
    ▼ summarizeCyphonResults()
    │
    ▼ AI + RESULTS_SUMMARY prompt
    │
    ▼
{ summary: "Google.com is...", highlights: [...] }

Key Concepts

Message Queue (MQQueue)

  • Jobs are processed asynchronously
  • Provides progress tracking
  • Handles failures gracefully
  • Supports concurrent processing

Feature Flags


if (!FeatureFlag.isEnabled("intel_cyphon", message.cx))
	throw new Error("Feature disabled.");

Cyphon can be enabled/disabled per organization.

Organization Scoping

All searches are scoped to the user's organization:


jobId = await searchManager.runSearch({
	org: await message.owner.getCurrentWorkspace(),
	// ...
});

Debugging Backend

Logs to Watch


console.log(`Job ID: ${jobId}`);

Look for job IDs in server logs to trace requests.

Common Issues

Issue Cause Solution
Empty commands AI didn't match any Check prompt or command keywords
Slow results Sources taking time Check individual source performance
Missing results Source not returning Debug specific search source
AI errors Prompt issues Check CYPHON_PROMPTS format