The Implementation Story: A Developer’s Log#

This page is where I’m documenting my notes while building Lynx FIM. It’s a record of the technical hurdles I’ve faced, the small wins, and what I’m learning as I dive into cybersecurity.

June 10, 2025: Getting Started#

I started by laying the groundwork for the CLI. I’m using cobra because it feels like the industry standard for Go tools. Getting the project structure right was my first challenge: Go has specific conventions for cmd/ and internal/, and I want to make sure I’m following them from day one.

I initially struggled with how to handle configuration. I want to keep the tool simple but flexible. I decided on viper for YAML support, which lets me define watch paths easily.

June 12, 2025: Cryptographic Wins#

Today, I implemented the core integrity logic: SHA-256 hashing and HMAC signing. This is the core of any FIM agent.

I learned that even simple things like hashing a string can be tricky. During my first unit test, I had a hash mismatch. I spent an hour debugging only to realize that my echo -n command and my Go test content had a slight difference in how they handled newlines.

I successfully implemented HMAC-SHA256 for signing payloads. This was a big “aha!” moment for me. I now understand how a secret key can be used to prove that a file (like our baseline) hasn’t been modified by an unauthorized party.

June 14, 2025: Walking the File System#

I’ve now implemented the “scanner” part of the agent. It recursively walks through the directories I’ve configured and gathers all the files it needs to hash.

One challenge I faced was handling relative paths. I want to make sure the agent is consistent, so I decided to resolve everything to absolute paths. This ensures that even if I run the agent from different directories, the “Source of Truth” remains stable.

June 16, 2025: Secure Baseline Storage#

This was a major milestone. I’ve combined the file scanner with my cryptographic logic to create the Baseline storage system.

I’ve implemented a system where the baseline.json file is signed with an HMAC. This means that if anyone tries to tamper with my baseline file (like changing a hash to hide their tracks), the agent will detect it immediately when it tries to load the file.

I learned about the importance of consistent JSON marshalling. To verify the signature, I have to make sure the data I’m re-hashing is exactly the same as what I signed originally. I found that resetting the Signature field to an empty string before marshalling for verification is a clean way to handle this.

June 18, 2025: Learning to Trust Tests#

As I move deeper into this project, I’ve decided to fully embrace Test-Driven Development (TDD). At first, it felt slow. Why write a test before the code? But as I worked on the hashing logic, I realized that in cybersecurity, “close enough” is a failure. If my integrity checks are slightly off, the whole system is useless. TDD forces me to define exactly what success looks like before I type a single line of implementation logic.

My workflow is now simple:

  1. Write a failing test for a small piece of functionality.
  2. Write just enough code to make the test pass.
  3. Clean up the code while ensuring the test stays green.

I applied this to the lynx init command today. By writing the test first, I was forced to think about the default configuration file format and ensure that even if I add new features later, the core initialization logic will still work as expected.

June 22, 2025: Coordinating the Baseline#

Today I tied everything together with the baseline command. This was my first time coordinating multiple internal packages (crypto, fs, config) to perform a complex task.

Using TDD to test the coordination logic in internal/app was helpful. I could verify that the whole process (scanning files, hashing them, and saving a signed baseline) was working correctly without having to manually run the CLI every time.

I learned about the value of mocks and environment variables in testing. To test the baseline command, I had to ensure the LYNX_HMAC_SECRET was correctly handled. Setting and unsetting environment variables in my tests made them reliable and isolated.

July 1, 2025: Into the Kernel - Real-time Monitoring#

Phase 1 was about the “Source of Truth” (the baseline). Phase 2 is about active defense. I’m starting to implement real-time monitoring using fsnotify.

I’ve been reading about how the Linux kernel handles file events. Instead of my agent constantly scanning the disk, which would be slow and resource-heavy, I can use inotify (via fsnotify) to have the kernel “ping” my agent the moment a file is touched. This is a huge step up in efficiency.

By the end of this month, I want lynx start to be a long-running process that watches my configured paths and logs any change immediately. I’m excited but also a bit nervous about handling the complexity of recursive directory watching.

July 3, 2025: Recursive Watching and Real-time Detection#

I’ve successfully implemented recursive directory watching today. This was a big technical hurdle for me. When a user creates a new folder within a watched path, my agent now automatically adds that folder to its monitoring queue.

I implemented a coordination loop that compares every file event against the memory-loaded baseline. If a file is modified, I re-hash it and compare the new signature with the old one. If it’s a new file, I log a warning. If it’s deleted, I log a critical alert.

I learned about the importance of handling OS events correctly. For example, when a new directory is created, fsnotify gives me a Create event. I have to immediately add that directory to the watcher so I don’t miss any files created inside it a split second later.

July 8, 2025: Structured Logging and the Start Command#

Phase 2 is now officially complete. I’ve wired up the real-time monitor to the CLI with the new lynx start command, and I’ve implemented structured JSON logging.

I learned that in the enterprise security world, simple text logs aren’t enough. Security Information and Event Management (SIEM) systems like Splunk or ELK need structured data. I decided to use Go’s standard library log/slog package to output all events as JSON.

Bringing everything together in cmd/start.go was satisfying. The agent now loads the configuration, verifies the signed baseline, initializes the JSON logger, and blocks while listening for file system events. It even handles termination signals (SIGINT, SIGTERM) gracefully.

August 3, 2025: Real-time Alerting and Manual Audits#

It is August 2025, and I’m entering the final phase of my initial learning roadmap. This month is about getting these alerts out of the log files and into a platform like Slack or Discord.

I successfully implemented the Webhook alerting pipeline today. Using TDD, I verified that my agent can now send a structured JSON payload to any configured webhook URL. This means I can get security alerts on my phone the moment a critical system file is touched.

I’ve also implemented the lynx verify command. This is useful for manual audits where I want to do a clean sweep and compare the entire system against the baseline without running a persistent agent.

I learned about the power of net/http and httptest in Go. Writing tests for the webhook required me to mock a web server, which was a great exercise in understanding how HTTP requests are actually structured and sent.

August 5, 2025: Speed and Security - Asynchronous Alerting#

As I tested the agent, I noticed a problem: if the webhook server is slow, my whole monitoring loop blocks while it waits for a response. In a security tool, that’s unacceptable. Every millisecond of delay is a window for an attacker.

I implemented an asynchronous AlertDispatcher today using Go’s channels and goroutines. Now, when the agent detects an anomaly, it simply “drops” the alert into a channel and gets back to monitoring immediately. A separate background process picks up the alert and handles the network delivery.

This was my first real experience with Go’s concurrency patterns in a production-like scenario. Learning how to use a select statement to handle both outgoing alerts and a “stop” signal was a major milestone for me. It makes the agent feel much more professional and robust.

August 8, 2025: The Final Connection#

Today I officially “closed the loop” by integrating the asynchronous alert dispatcher into the lynx start command.

It was a moment of satisfaction to see all the pieces working together. The agent now initializes the monitor, starts the background dispatcher, and then sits in a non-blocking loop waiting for file events. When an anomaly is detected, it’s logged to JSON and then immediately “fired off” to the webhook channel.

I learned about the importance of channel buffering. By giving my channels a small buffer, I’ve made the system even more resilient to bursts of file system activity. It’s a small detail, but in a security tool, it’s the difference between catching every event and missing a critical breach.

August 15, 2025: Ready for Deployment - Build Automation#

As I wrap up this project, I’ve moved from writing code to thinking about how others will use it. I’ve implemented a Makefile to handle building, testing, and cross-compiling the Lynx FIM agent.

With one command, I can now run my entire test suite and build binaries for both amd64 and arm64 Linux servers. This is a major step toward making the agent “production-ready.” It feels like I’ve built a real tool, not just a learning project.

I learned that automation is just as important as the code itself. By building the testing into my Makefile, I’ve ensured that I never accidentally ship a binary that hasn’t passed all my integrity checks.

August 15, 2025: Final Audit and Proof of Concept#

Today I performed the final end-to-end manual test of the Lynx FIM agent. I’ve vetted the codebase with go fmt and go vet, and then I ran the agent through its paces in a simulated security scenario.

Seeing the lynx verify command catch my manual tampering with a “critical” test file was rewarding. But even better was watching the structured JSON logs populate in real-time as I modified files while the agent was running in the background.

August 28, 2025: The Final Layer - CI/CD and Portability#

The final piece of the puzzle was automating the build process using GitHub Actions.

I learned that because Go binaries are statically compiled, I don’t need to target specific Linux distros like Ubuntu or CentOS. As long as I target the correct architecture (AMD64 or ARM64), the binary carries everything it needs to run.

I successfully set up a GitHub Workflow that automatically builds and tests the agent on every push. It’s a professional touch that ensures the project is always in a “shippable” state. It’s the perfect way to conclude this 2-month intensive learning cycle.

August 31, 2025: The Webhook Mystery - Discord Compatibility#

I hit a major roadblock today: my webhook alerts were sending successfully from the agent, but nothing was appearing in Discord.

I dug into the Discord Webhook documentation and realized my mistake. Discord (and Slack) don’t just display a raw JSON dump. They expect a specific field, usually content for Discord or text for Slack, to actually show a message. My original JSON payload was being ignored because it didn’t have these fields.

I updated my Alert struct to include both content and text fields. I also updated the NewAlert function to automatically format a nice, readable summary with emojis and bold text. Now, the alerts look professional and are instantly visible in Discord.

August 31, 2025: Beyond “Critical” - Dynamic Severities#

As I refined the agent, I realized that labeling every single event as “CRITICAL” was creating too much noise. A new file being created in a watched directory is important (a WARNING), but a monitored configuration file being deleted or modified is an emergency (a CRITICAL event).

I implemented a new Incident struct to replace the simple string messages I was using before. This allows the monitor to pass detailed metadata: like severity, event type, and file path, all the way up to the CLI and the webhooks.

I ran into a tricky bug where rapid file writes were generating duplicate events in my tests. I learned the importance of “draining” channels and adding small delays to ensure my TDD assertions were reliable and focused on the right data.

September 1, 2025: Quality over Speed - Timeline Extension#

I’ve decided to extend my learning roadmap into September. Originally, I thought two months would be enough, but as I got deeper into the security logic, I realized there was more to document and refine. I want to make sure I don’t saturate the project with too many rushed changes.

This month is about clarifying the “Security Logic” of the tool. I’ve formally documented the criteria for my CRITICAL and WARNING severity levels. This helps anyone using the tool understand exactly why they are being alerted.

September 5, 2025: Protecting the Source of Truth - Ignores and Config Integrity#

As I moved into September, I focused on two critical features: a .gitignore-style mechanism for monitoring and ensuring the integrity of the configuration itself.

I implemented ignored_patterns in the configuration. This allows users to exclude noisy files (like .tmp or .swp) while still watching the rest of a directory. But more importantly, I realized that the configuration itself is a target. If an attacker can modify the ignore list, they can hide their tracks.

I now hash the config.yaml file and store that hash in the baseline metadata. Every time the agent starts, it re-hashes the config and compares it to the “locked” version in the baseline. If they don’t match, the agent refuses to start. It’s a “Source of Truth” for the “Source of Truth.”

September 15, 2025: Taming the Noise - Event Debouncing#

As I tested the agent with real-world editors like Vim and Nano, I noticed a major issue: a single file save was triggering up to four different alerts.

I learned that editors don’t just “write” to a file. They perform an “atomic save”: creating temporary files, deleting the original, and then renaming the new one into place. fsnotify sees every single one of these steps as a separate event.

I implemented an event debouncer. When a file event occurs, the agent now waits for a short cooldown period (500ms). If more events arrive for that same file during the window, the timer resets. Once the activity settles, the agent only processes the final state of the file. This reduced my alert spam from 4-5 reports down to just 1 accurate FILE_MODIFIED incident.

Systems programming requires handling the messiness of the OS. What looks like one action to a human is often a dozen rapid-fire events to the kernel.

September 20, 2025: Professional Polish - Semantic Alerting#

As I reviewed the agent’s output, I realized that while emojis looked “cool” initially, they were actually bloating the logs and the webhook messages. In a high-stakes security environment, clarity is more important than aesthetics.

I rewrote the alert formatting to use semantic labeling. Now, instead of icons, alerts are prefixed with clear, text-based indicators like [CRITICAL] or [WARNING]. This makes the data easier to parse for both humans and automated scripts.

I also formally documented what the “Agent” field means. It’s the unique identifier for the host reporting the event. This is crucial for “Distributed Defense”: if I deploy Lynx to 50 different servers, I need to know exactly which one is being attacked based on its name.

Professional software should be “signal over noise.” Stripping away the fluff makes the tool feel much more serious and reliable.

September 25, 2025: Sounding the Alarm - Self-Protection Alerting#

Today I realized a critical gap in my security tool: if an attacker tampered with the baseline or the configuration, the agent would log an error and exit, but it wouldn’t tell anyone why. A silent failure is an attacker’s best friend.

I implemented self-protection alerting. Now, when the agent detects a signature mismatch or a configuration change during startup, it doesn’t just die: it sends a final, synchronous emergency alert via the webhook before shutting down. This ensures that the security team is immediately notified that the system’s “Source of Truth” has been compromised.

A security agent must be able to defend itself. By sounding the alarm even as it fails, Lynx FIM ensures total visibility into the system’s integrity state.

Today marks the final day of my three-month intensive build. I wanted to ensure the project was not only technically sound but also visually and legally complete.

I’ve added actual screenshots of the Discord alerts to the documentation and README. Seeing the “Red” alerts in a real Discord channel is the ultimate proof that the alerting pipeline I built is robust and production-ready.

I’ve implemented a custom license. As this project represents hundreds of hours of learning and building, I want to ensure my work is protected while still being available for others to learn from. The license mandates attribution and gives me full discretion over how the code is used or modified.

This project has taken me from a Go novice to building a multi-threaded, cryptographic security agent. I’m ready for whatever comes next in my cybersecurity career.

Technical Achievements (Project Finalized):#

  • Verified SHA-256 hashing for files.
  • Implemented constant-time HMAC comparison to prevent timing attacks.
  • Established a strict test-driven development (TDD) workflow.
  • Recursive file system traversal with absolute path resolution.
  • HMAC-signed JSON storage for the baseline with tamper detection.
  • CLI implementation for lynx init, lynx baseline, lynx start, and lynx verify.
  • Core real-time monitoring with fsnotify.
  • Recursive directory watching and anomaly detection logic.
  • Structured JSON logging and Asynchronous Webhook alerting.
  • Fully integrated, non-blocking alerting pipeline.
  • Automated build system and cross-platform CI/CD.
  • Verified Discord/Slack compatibility with visual proof.
  • Implemented custom ownership license and final visual assets.

“A project is never truly finished, it’s just ready for its next version. This journey has given me the foundation I need for a career in cybersecurity.” - Signing off on the Summer 2025 roadmap.


🗺️ Navigation#