[New Module] WhatChanged - Find out why the Apply Config button is appearing

Yes, another vibe coded module! I know everyone’s excited.

I’ve seen posts before about this, like this one:

What I’ve worked on with ChatGPT’s Sol 5.6 is a module and a ‘tripwire’, is it perfect? No. I would like to get there. I have taken into account the issues Tom Ray mentioned in his reply in the above thread, and the module includes a python agent that watches for file changes, as well as database changes, and tries to only watch the things that are within the realm of things you can change, so not the CEL/CDR, etc. I use it on my PBX and every time I make a change, I check to make sure it shows up in the tripwire module. This even finds module changes done from the command line fwconsole, so the real goal: I just logged in, I didn’t change anything, the Apply Changes button is up there… I don’t know what’s going to happen. Now I have a chance.

At the moment I would like to do this as a closed alpha before making the repository open. I’m not just giving out binary blobs though, I will give you a read-only deploy key and you can read the code (or have your agent do it) before running anything. Also I just added a inferred blame feature so you can see which admin probably did each change.

I have ended up just making it public. Please submit issues on GitHub.

The long install command is because there’s no guarantee your location is standard and I want to be thorough. It also is tested working on versions 14 through 17.

This is something my users have asked for in the past, so I took a quick look at the code.

Some opinionated suggestions from a first glance:

  • Are you aware of a module that triggers the “need reload” button due to changed files within the module directory? It seems like a very heavy check to iterate every single file (esp with ucp or pm2’s node_modules directory) looking for changes (also note this duplicates the function of module signatures)
  • I think you’re limiting yourself by trying to support v14 and, by extension, PHP 5 – I’d not worry about anything older than 16, personally
  • You should just use the kvstore instead of going to the effort of making a database table that will only hold a single record
  • You’ve hard coded /var/lib/asterisk in a few places, but this should be pulled from the ASTVARLIB setting, as you are with AMPWEBROOT
  • Same with /etc/asterisk and ASTETCDIR
  • If you want to encourage contributions, you should use PSR-12 style, including docblocks on all your methods and functions
  • You don’t need functions.inc.php at all, you have an install method in the class – IIRC that’s been used since v13
  • I’d suggest you’ll find managing HTML much easier if you move it to views, then use load_view() within a static class method, and leaving page.pendingchanges.php essentially empty except for calling that method
  • Your install instructions should just say sudo /var/lib/asterisk/bin/fwconsole ma install https://xxx followed by the watcher install – even better, why not install the watcher from the class install method?
  • In your watcher install script, you’re very eager to spawn new processes. e.g. os_like=$(sed -n 's/^ID_LIKE=//p' "$os_release" 2>/dev/null | head -n 1 | tr -d '"' || true) could be simply os_like=$(source "$os_release" && echo $ID_LIKE)
  • Your database setup script doesn’t look like it accounts for a custom value in AMPDBPORT or AMPDBSOCK

I may give a try in our test environment, will open issues as needed.

I have passed this along and gotten this response from Sol.

Thank you for taking the time to review this. This was exactly the kind of FreePBX-specific feedback I was hoping for.

I went through your suggestions and made several changes based directly on your review:

  • It no longer recursively hashes every file in every installed module. It now watches the modules database table and the stable module.xml/module.sig release markers. FreePBX’s existing module-signature system remains responsible for exhaustive file-integrity checking.

  • The framework-only fallback baseline now uses the module’s native BMO key/value storage instead of a custom one-row table. Existing baselines are migrated automatically.

  • It follows the configured AMPWEBROOT, ASTETCDIR, and ASTVARLIBDIR/ASTVARLIB values instead of assuming standard filesystem paths.

  • The obsolete functions.inc.php lifecycle bootstrap has been removed.

  • The watcher’s environment and systemd filesystem protections are regenerated using the actual FreePBX paths.

I also caught the two words you added afterward concerning AMPDBSOCK. You were correct: my first revision accounted for a custom AMPDBPORT, but not a custom database socket.

That is now fixed in 17.0.1.7:

  • The setup program reads both AMPDBPORT and AMPDBSOCK.

  • When AMPDBSOCK is configured, the MariaDB account setup uses that socket explicitly.

  • The watcher receives the same socket path and connects through PyMySQL’s Unix-socket transport.

  • When no socket is configured, it continues to use AMPDBHOST and AMPDBPORT over TCP.

  • Socket paths are validated as safe absolute paths and covered by installer and watcher tests.

I kept FreePBX 14 support because people specifically volunteered legacy systems for testing, and the same unified module archive currently passes real-image Module Admin installation and staged-change/Apply Config lifecycle tests on FreePBX 14, 15, 16, and 17. I agree that nobody should choose PHP 5.6 for a new deployment, but compatibility with an existing PBX remains useful here.

I deliberately did not make the BMO class silently install the watcher service. That operation creates a database account, installs a systemd service, and adds an Apache/PHP request sensor, so I believe it should remain an explicit root-level installation action rather than happening merely because someone enabled a GUI module.

The larger PSR-12/docblock and view-template cleanup is still worthwhile, but I kept it separate from this storage, installer, and monitoring maintenance work to reduce cross-version regression risk.

The complete FreePBX 17 Docker gate passed after these changes, along with real-image FreePBX 14, 15, and 16 lifecycle gates.

Thanks again—your review has materially improved the project. Further criticism and testing are very welcome.

Went ahead and did the PSR-12 refactor.

I’ve published another update: Pending Changes Tripwire 17.0.2.0 alpha.

This release is primarily an architectural cleanup based on the code-quality feedback here:

  • The module now has a PSR-4-compatible internal class structure under src/.

  • The conventional FreePBX Pendingchanges.class.php BMO and page.pendingchanges.php files remain, but they are now thin framework entry points.

  • Baseline storage, database and file snapshots, redaction, diff generation, watcher health, request handling, presentation logic, and views are separated into focused classes.

  • The PHP source passes a checked-in PSR-12 PHP_CodeSniffer ruleset.

  • Composer metadata documents the PSR-4 namespace and provides a repeatable style check.

There are two documented compatibility exceptions to the PSR-12 rules: FreePBX 14/15 compatibility requires PHP 5.6, which cannot declare visibility on class constants, and the conventional FreePBX BMO entry point must register the module autoloader while declaring the framework class.

This remains one unified module archive for FreePBX 14, 15, 16, and 17. The identical archive passed:

  • The complete disposable FreePBX 17 functional gate

  • Real Module Admin installation on FreePBX 14, 15, and 16 images

  • Staged configuration-drift detection

  • Apply Config and baseline refresh

  • Final clean-state verification

  • PHP syntax and rendering checks on PHP 5.6, 7.4, and 8.2

The watcher remains version 0.1.6 because its protocol and behavior did not change in this release. The refactor is intended to make future coverage additions and community review considerably easier without altering the current security or privacy boundaries.

The release assets, checksums, and detached signatures are available on GitHub. FreePBX may continue to describe the module signature as locally signed or untrusted until Sangoma certifies my signing key.

My guy, this is not your coworker. You didn’t pass it along, you input it into a statistical model. On that subject, another way of encouraging open source participation is not doing monolithic commits that touch 3 dozen files at a time. People should be able to see what’s changing and why. (This will also improve uptake among PBX admins who actually look at the code they’re installing, though this is admittedly a pretty small audience.)

You couldn’t do that from the GUI anyway. Just check the SAPI and uid for root and CLI. Also I didn’t check but if you’re assuming everyone uses Apache, you’re assuming incorrectly.

I’m not so sure the PSR-4 stuff is an improvement in terms of understanding the code, but that may just be me. Looks improved otherwise, we will likely deploy in our test environment in a month or two. :+1:

And this one:

That’s true, and I am curious to see what he’s done, but it’s still private as far as I can tell from the thread that’s been inactive since May. I will admit, I did not find that when searching to see if it had been done before. I’m going to blame it on not having “Apply Config” in the title, it is really a key “SEO” point, optimizing for the forum search engine.

Mine was not “hey, look at me, I made this for everyone”, it’s really a project for myself that I wanted to make available as well.

I don’t think Sol is a coworker, but I get really irritated when people have AI write for them and then they pretend it was their own work, so I try to make it very clear.

nginx compatibility added, and tested in Docker labs. (I do test everything, no blind releases with fingers crossed.)

Release Pending Changes Tripwire 17.0.2.2 alpha · tomck/WhatChanged · GitHub for that.

P.S. I sent in an e-mail to code@sangoma to get signed, please review, thank you.

Let me know your github or email and I can give you access / token if you want. :+1:

Github is tomck - didn’t mean to step on your toes or anything, how are you feeling with regard to the two projects?

I’ve started stating this clearly in my READMEs. It’s important that every commit includes the Assisted-by comment where appropriate. Not only does it provide a useful historical reference, it also makes clear to anyone reviewing the code that AI played a part in that particular commit, rather than simply the project as a whole. Often, the model used changes too.


AI-Assisted Contributions and Disclosure

This module has been developed with AI assistance for code generation, review, testing, and documentation. Generative AI assistance must be disclosed in every commit containing AI-assisted changes:

Assisted-by: AGENT_NAME:MODEL_VERSION

For example: Assisted-by: GitHub-Copilot:gpt-5.6-sol

The human contributor remains solely responsible for the contribution. AI tools must not be listed as co-authors.


As an aside, AI assistance is a good thing in 2026 and there is no shame in it, so your opening to this thread is unnecessarily self-deprecating. We all need to get used to seeing a lot more of this, and it’s welcome. The project is kept alive by all contributions.

Yes, another vibe coded module! I know everyone’s excited.

IMO, it doesn’t set the right tone for this new community module announcement.

This module could prove to be a very useful addition to FreePBX. I cannot imagine a single time I have logged into a PBX, seen the Apply Config button, and not hesitated before pressing it.

Good job so far and good luck with it.

Not at all! The more the marrier, it’s the way of open source!

While our modules both try to help with the issue of visibility, I’d say mine is more audit/retrospective than yours which seems to be predictive — which is super awesome! I can 100% relate to @kierknoby when he talks about logging in to find the red “Apply” button, specifically after making NO changes since the last apply haha.

So this is really great, keep it up! I’ve added you to my repo in case Sol can glean anything useful from it. :+1:

Really pleasant co-ordination and shared approach here – keeping the humans in the loop :people_holding_hands: :heart:

If y’all are interested in this becoming part of official FreePBX repos, then please keep in mind the Assisted-by tag for AI boosts and work in such a way that you’ll be able to sign off on the project CLA (which you may have already done e.g. if you ever submitted patches to the main FreePBX project repos, this is automated part of that process.)

I had the Co-Authored tag because it makes it show up on Github, I can switch it to Assisted-By with revisionist history if it’s necessary. It’s not that I want to be a part of the official repos, it’s just that I want the GPG key signed so the un-signed message goes away. Is there a middle ground here or is assisted-by required for getting my key signed?

That’s not the intent of that tag – its always been for people, not bots.

Aside: we’ll need to update the repos with more instructions – added an issue [improvement]: add AGENTS.md to help bots behave better · Issue #1334 · FreePBX/issue-tracker · GitHub